set token location, support OPEN_PARENS, CLOSE_PARENS, SEMICOLON, PUBLIC,
authorJürg Billeter <j@bitron.ch>
Mon, 24 Apr 2006 06:58:11 +0000 (06:58 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Mon, 24 Apr 2006 06:58:11 +0000 (06:58 +0000)
2006-04-24  Jürg Billeter  <j@bitron.ch>

* valac/scanner.l: set token location, support OPEN_PARENS,
  CLOSE_PARENS, SEMICOLON, PUBLIC, STATIC
* valac/parser.y: save symbol location, output exact error location,
  support method declarations
* valac/context.h: add ValaLocation, ValaMethod, and ValaFormalParameter
  structs, add location to ValaClass and ValaTypeReference structs
* valac/context.c: output error location, support method declarations
* valac/generator.c: support method declarations
* valac/driver.c: add comment
* tests/test-004.vala: test method declaration

svn path=/trunk/; revision=3

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

index 9af11ba..019cd38 100644 (file)
@@ -1,3 +1,16 @@
+2006-04-24  Jürg Billeter  <j@bitron.ch>
+
+       * valac/scanner.l: set token location, support OPEN_PARENS,
+         CLOSE_PARENS, SEMICOLON, PUBLIC, STATIC
+       * valac/parser.y: save symbol location, output exact error location,
+         support method declarations
+       * valac/context.h: add ValaLocation, ValaMethod, and ValaFormalParameter
+         structs, add location to ValaClass and ValaTypeReference structs
+       * valac/context.c: output error location, support method declarations
+       * valac/generator.c: support method declarations
+       * valac/driver.c: add comment
+       * tests/test-004.vala: test method declaration
+
 2006-04-22  Jürg Billeter  <j@bitron.ch>
 
        * valac/scanner.l: support DOT, COLON, and COMMA
diff --git a/vala/tests/test-004.vala b/vala/tests/test-004.vala
new file mode 100644 (file)
index 0000000..7375568
--- /dev/null
@@ -0,0 +1,9 @@
+namespace Maman {
+       class Bar {
+               public void do_action () {
+               }
+       }
+       
+       class SubBar : Bar {
+       }
+}
index 481e860..baa534d 100644 (file)
@@ -60,6 +60,18 @@ vala_symbol_new (ValaSymbolType type)
 }
 
 static void
+err (ValaLocation *location, const char *format, ...)
+{
+       va_list args;
+       va_start (args, format);
+       fprintf (stderr, "%s:%d:%d: ", location->source_file->filename, location->lineno, location->colno);
+       vfprintf (stderr, format, args);
+       fprintf (stderr, "\n");
+       va_end (args);
+       exit (1);
+}
+
+static void
 vala_context_add_symbols_from_namespace (ValaContext *context, ValaNamespace *namespace)
 {
        ValaSymbol *ns_symbol, *class_symbol;
@@ -82,8 +94,7 @@ vala_context_add_symbols_from_namespace (ValaContext *context, ValaNamespace *na
                
                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);
+                       err (class->location, "error: class ´%s.%s´ already defined", namespace->name, class->name);
                }
 
                class_symbol = vala_symbol_new (VALA_SYMBOL_TYPE_CLASS);
@@ -101,6 +112,11 @@ vala_context_add_fundamental_symbols (ValaContext *context)
        
        context->root = vala_symbol_new (VALA_SYMBOL_TYPE_ROOT);
        
+       /* void */
+       symbol = vala_symbol_new (VALA_SYMBOL_TYPE_VOID);
+       g_hash_table_insert (context->root->symbol_table, "void", symbol);
+
+       /* namespace G */       
        namespace = g_new0 (ValaNamespace, 1);
        namespace->name = g_strdup ("G");
        namespace->lower_case_cname = g_strdup ("g_");
@@ -155,9 +171,11 @@ vala_context_resolve_type_reference (ValaContext *context, ValaNamespace *namesp
                
                /* FIXME: look in namespaces specified by using directives */
 
-               if (type_symbol == NULL) {
+               if (type_symbol != NULL) {
+                       type_reference->namespace_name = "";
+               } else {
                        /* specified namespace not found */
-                       fprintf (stderr, "Error: Specified type '%s' not found.\n", type_reference->type_name);
+                       err (type_reference->location, "error: specified type ´%s´ not found", type_reference->type_name);
                        exit (1);
                }
        } else {
@@ -165,49 +183,61 @@ vala_context_resolve_type_reference (ValaContext *context, ValaNamespace *namesp
                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);
+                       err (type_reference->location, "error: specified namespace '%s' not found", type_reference->namespace_name);
                }
 
                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);
+                       err (type_reference->location, "error: specified type ´%s´ not found in namespace ´%s´", type_reference->type_name, type_reference->namespace_name);
                }
        }
        
-       if (type_symbol->type == VALA_SYMBOL_TYPE_CLASS) {
+       if (type_symbol->type == VALA_SYMBOL_TYPE_VOID ||
+           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);
+               err (type_reference->location, "error: specified symbol ´%s´ is not a type", type_reference->type_name);
+       }
+}
+
+static void
+vala_context_resolve_types_in_method (ValaContext *context, ValaMethod *method)
+{
+       GList *l;
+       
+       vala_context_resolve_type_reference (context, method->class->namespace, method->return_type);
+       
+       for (l = method->formal_parameters; l != NULL; l = l->next) {
+               ValaFormalParameter *formal_parameter = l->data;
+               
+               vala_context_resolve_type_reference (context, method->class->namespace, formal_parameter->type);
+               if (formal_parameter->type->symbol->type == VALA_SYMBOL_TYPE_VOID) {
+                       err (formal_parameter->location, "error: method parameters cannot be of type `void`");
+               }
        }
 }
 
 static void
-vala_context_resolve_types_in_class (ValaContext *context, ValaNamespace *namespace, ValaClass *class)
+vala_context_resolve_types_in_class (ValaContext *context, 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);
+               vala_context_resolve_type_reference (context, class->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);
+                               err (type_reference->location, "error: more than one base class specified in class ´%s.%s´", class->namespace->name, class->name);
                        }
                        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);
+                               err (type_reference->location, "error: ´%s.%s´ cannot be subtype of ´%s.%s´", class->namespace->name, class->name, class->namespace->name, class->name);
                        }
                        /* 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);
+                       err (type_reference->location, "error: ´%s.%s´ cannot be subtype of ´%s.%s´", class->namespace->name, class->name, type_reference->namespace_name, type_reference->type_name);
                }
        }
        
@@ -215,6 +245,11 @@ vala_context_resolve_types_in_class (ValaContext *context, ValaNamespace *namesp
                ValaSymbol *symbol = g_hash_table_lookup (context->root->symbol_table, "object");
                class->base_class = symbol->class;
        }
+       
+       for (l = class->methods; l != NULL; l = l->next) {
+               ValaMethod *method = l->data;
+               vala_context_resolve_types_in_method (context, method);
+       }
 }
 
 static void
@@ -225,7 +260,7 @@ vala_context_resolve_types_in_namespace (ValaContext *context, ValaNamespace *na
        for (cl = namespace->classes; cl != NULL; cl = cl->next) {
                ValaClass *class = cl->data;
                
-               vala_context_resolve_types_in_class (context, namespace, class);
+               vala_context_resolve_types_in_class (context, class);
        }
 }
 
index 92daabe..b1c3ecb 100644 (file)
 #include <glib.h>
 
 typedef enum _ValaSymbolType ValaSymbolType;
+typedef enum _ValaMethodFlags ValaMethodFlags;
 
 typedef struct _ValaContext ValaContext;
 typedef struct _ValaSymbol ValaSymbol;
 typedef struct _ValaSourceFile ValaSourceFile;
+typedef struct _ValaLocation ValaLocation;
 typedef struct _ValaNamespace ValaNamespace;
 typedef struct _ValaClass ValaClass;
+typedef struct _ValaMethod ValaMethod;
 typedef struct _ValaTypeReference ValaTypeReference;
+typedef struct _ValaFormalParameter ValaFormalParameter;
 
 enum _ValaSymbolType {
        VALA_SYMBOL_TYPE_ROOT,
        VALA_SYMBOL_TYPE_NAMESPACE,
+       VALA_SYMBOL_TYPE_VOID,
        VALA_SYMBOL_TYPE_CLASS,
 };
 
+enum _ValaMethodFlags {
+       VALA_METHOD_PUBLIC = 0x01,
+       VALA_METHOD_STATIC = 0x02,
+};
+
 struct _ValaContext {
        GList *source_files;
        ValaSymbol *root;
@@ -56,6 +66,12 @@ struct _ValaSourceFile {
        GList *namespaces;
 };
 
+struct _ValaLocation {
+       ValaSourceFile *source_file;
+       int lineno;
+       int colno;
+};
+
 struct _ValaNamespace {
        char *name;
        ValaSymbol *symbol;
@@ -66,19 +82,39 @@ struct _ValaNamespace {
 
 struct _ValaClass {
        char *name;
+       ValaLocation *location;
        ValaNamespace *namespace;
        ValaClass *base_class;
        GList *base_types;
+       GList *methods;
        char *lower_case_cname;
        char *upper_case_cname;
 };
 
+struct _ValaMethod {
+       char *name;
+       ValaLocation *location;
+       ValaClass *class;
+       ValaTypeReference *return_type;
+       GList *formal_parameters;
+       ValaMethodFlags modifiers;
+       char *cdecl1;
+       char *cdecl2;
+};
+
 struct _ValaTypeReference {
        char *namespace_name;
        char *type_name;
+       ValaLocation *location;
        ValaSymbol *symbol;
 };
 
+struct _ValaFormalParameter {
+       char *name;
+       ValaTypeReference *type;
+       ValaLocation *location;
+};
+
 ValaContext *vala_context_new ();
 void vala_context_free (ValaContext *context);
 void vala_context_parse (ValaContext *context);
index 63d72e0..ce6d085 100644 (file)
@@ -34,6 +34,7 @@ driver_main (char **sources, char *directory)
         * Copy namespace and type names from parse tree into symbol tables
         * Resolve type references in parse tree
         * Load metadata from parse tree into symbol tables
+        * Add memory management calls
         * Generate code
         */
        
index 26153b6..4498668 100644 (file)
@@ -55,7 +55,112 @@ filename_to_define (const char *filename)
 }
 
 static void
-vala_code_generator_process_class (ValaCodeGenerator *generator, ValaClass *class)
+vala_code_generator_process_methods1 (ValaCodeGenerator *generator, ValaClass *class)
+{
+       GList *l;
+
+       char *camel_case;
+       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;
+               
+               char *method_return_type_cname = g_strdup_printf ("%s%s", method->return_type->namespace_name, method->return_type->type_name);
+               char *method_cname = g_strdup_printf ("%s%s_%s", ns_lower, lower_case, method->name);
+               char *parameters;
+               GList *parameter_list = NULL;
+               if ((method->modifiers & VALA_METHOD_STATIC) == 0) {
+                       parameter_list = g_list_append (parameter_list, g_strdup_printf ("%s%s *self", namespace->name, class->name));
+               }
+               
+               GList *pl;
+               for (pl = method->formal_parameters; pl != NULL; pl = pl->next) {
+                       ValaFormalParameter *param = pl->data;
+                       parameter_list = g_list_append (parameter_list, g_strdup_printf ("%s%s *%s", param->type->symbol->class->namespace->name, param->type->symbol->class->name, param->name));
+               }
+               
+               if (parameter_list == NULL) {
+                       parameters = g_strdup ("");
+               } else {
+                       parameters = parameter_list->data;
+                       GList *sl;
+                       for (sl = parameter_list->next; sl != NULL; sl = sl->next) {
+                               parameters = g_strdup_printf ("%s, %s", parameters, 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, "\n");
+}
+
+static void
+vala_code_generator_process_methods2 (ValaCodeGenerator *generator, ValaClass *class)
+{
+       GList *l;
+
+       char *camel_case;
+       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_PUBLIC) {
+                       fprintf (generator->h_file, "%s %s;\n", method->cdecl1, method->cdecl2);
+               }
+
+               fprintf (generator->c_file, "%s\n", method->cdecl1);
+               fprintf (generator->c_file, "%s\n", method->cdecl2);
+               fprintf (generator->c_file, "{\n");
+               fprintf (generator->c_file, "}\n");
+               fprintf (generator->c_file, "\n");
+       }
+       fprintf (generator->h_file, "\n");
+
+       /* constructors */
+       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_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");
+}
+
+static void
+vala_code_generator_process_class1 (ValaCodeGenerator *generator, ValaClass *class)
 {
        ValaNamespace *namespace = class->namespace;
 
@@ -83,7 +188,27 @@ vala_code_generator_process_class (ValaCodeGenerator *generator, ValaClass *clas
        fprintf (generator->h_file, "typedef struct _%s %s;\n", camel_case, camel_case);
        fprintf (generator->h_file, "typedef struct _%sClass %sClass;\n", camel_case, camel_case);
        fprintf (generator->h_file, "\n");
+       
+       vala_code_generator_process_methods1 (generator, class);
+}
+
+static void
+vala_code_generator_process_class2 (ValaCodeGenerator *generator, ValaClass *class)
+{
+       ValaNamespace *namespace = class->namespace;
+
+       char *camel_case;
+       char *ns_lower;
+       char *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 = class->lower_case_cname;
+       char *upper_case = class->upper_case_cname;
 
+       /* structs */
        fprintf (generator->h_file, "struct _%s {\n", camel_case);
        fprintf (generator->h_file, "\t%s%s parent;\n", class->base_class->namespace->name, class->base_class->name);
        fprintf (generator->h_file, "};\n");
@@ -98,19 +223,8 @@ vala_code_generator_process_class (ValaCodeGenerator *generator, ValaClass *clas
        fprintf (generator->h_file, "GType %s%s_get_type () G_GNUC_CONST;\n", ns_lower, lower_case);
        fprintf (generator->h_file, "\n");
        
-       /* constructors */
-       fprintf (generator->c_file, "static void\n");
-       fprintf (generator->c_file, "%s%s_init (%s *self)\n", ns_lower, lower_case, camel_case);
-       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 (%sClass *klass)\n", ns_lower, lower_case, camel_case);
-       fprintf (generator->c_file, "{\n");
-       fprintf (generator->c_file, "}\n");
-       fprintf (generator->c_file, "\n");
-
+       vala_code_generator_process_methods2 (generator, class);
+       
        /* type initialization function */
        fprintf (generator->c_file, "GType\n");
        fprintf (generator->c_file, "%s%s_get_type ()\n", ns_lower, lower_case);
@@ -139,11 +253,20 @@ vala_code_generator_process_class (ValaCodeGenerator *generator, ValaClass *clas
 }
 
 static void
-vala_code_generator_process_namespace (ValaCodeGenerator *generator, ValaNamespace *namespace)
+vala_code_generator_process_namespace1 (ValaCodeGenerator *generator, ValaNamespace *namespace)
 {
        GList *l;
        for (l = namespace->classes; l != NULL; l = l->next) {
-               vala_code_generator_process_class (generator, l->data);
+               vala_code_generator_process_class1 (generator, l->data);
+       }
+}
+
+static void
+vala_code_generator_process_namespace2 (ValaCodeGenerator *generator, ValaNamespace *namespace)
+{
+       GList *l;
+       for (l = namespace->classes; l != NULL; l = l->next) {
+               vala_code_generator_process_class2 (generator, l->data);
        }
 }
 
@@ -186,10 +309,17 @@ vala_code_generator_process_source_file (ValaCodeGenerator *generator, ValaSourc
        fprintf (generator->c_file, "#include \"%s\"\n", g_path_get_basename (h_filename));
        fprintf (generator->c_file, "\n");
        
-       vala_code_generator_process_namespace (generator, source_file->root_namespace);
+       vala_code_generator_process_namespace1 (generator, source_file->root_namespace);
        GList *l;
+
+       for (l = source_file->namespaces; l != NULL; l = l->next) {
+               vala_code_generator_process_namespace1 (generator, l->data);
+       }
+
+       vala_code_generator_process_namespace1 (generator, source_file->root_namespace);
+
        for (l = source_file->namespaces; l != NULL; l = l->next) {
-               vala_code_generator_process_namespace (generator, l->data);
+               vala_code_generator_process_namespace2 (generator, l->data);
        }
 
        fprintf (generator->h_file, "G_END_DECLS\n");
index 4dd5975..7b36ec5 100644 (file)
@@ -23,6 +23,7 @@
 %{
 #include <stdlib.h>
 #include <stdio.h>
+#include <string.h>
 
 #include <glib.h>
 
@@ -86,8 +87,21 @@ camel_case_to_upper_case (const char *camel_case)
        return str;
 }
 
-ValaSourceFile *current_source_file;
-ValaNamespace *current_namespace;
+static ValaSourceFile *current_source_file;
+static ValaNamespace *current_namespace;
+static ValaClass *current_class;
+static ValaMethod *current_method;
+
+ValaLocation *get_location (int lineno, int colno)
+{
+       ValaLocation *loc = g_new0 (ValaLocation, 1);
+       loc->source_file = current_source_file;
+       loc->lineno = lineno;
+       loc->colno = colno;
+       return loc;
+}
+
+#define current_location(token) get_location (token.first_line, token.first_column)
 %}
 
 %defines
@@ -96,25 +110,39 @@ ValaNamespace *current_namespace;
 %pure_parser
 %glr-parser
 %union {
+       int num;
        char *str;
        GList *list;
        ValaTypeReference *type_reference;
+       ValaFormalParameter *formal_parameter;
 }
 
 %token OPEN_BRACE "{"
 %token CLOSE_BRACE "}"
+%token OPEN_PARENS "("
+%token CLOSE_PARENS ")"
 %token DOT "."
 %token COLON ":"
 %token COMMA ","
+%token SEMICOLON ";"
 
 %token NAMESPACE "namespace"
 %token CLASS "class"
+%token PUBLIC "public"
+%token STATIC "static"
 %token <str> IDENTIFIER "identifier"
 
 %type <list> opt_class_base
 %type <list> class_base
 %type <list> type_list
 %type <type_reference> type_name
+%type <list> opt_formal_parameter_list
+%type <list> formal_parameter_list
+%type <list> fixed_parameters
+%type <formal_parameter> fixed_parameter
+%type <num> opt_method_modifiers
+%type <num> method_modifiers
+%type <num> method_modifier
 
 %%
 
@@ -179,13 +207,14 @@ type_declaration
 class_declaration
        : CLASS IDENTIFIER opt_class_base
          {
-               ValaClass *class = g_new0 (ValaClass, 1);
-               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);
+               current_class = g_new0 (ValaClass, 1);
+               current_class->name = g_strdup ($2);
+               current_class->base_types = $3;
+               current_class->location = current_location (@2);
+               current_class->namespace = current_namespace;
+               current_class->lower_case_cname = camel_case_to_lower_case (current_class->name);
+               current_class->upper_case_cname = camel_case_to_upper_case (current_class->name);
+               current_namespace->classes = g_list_append (current_namespace->classes, current_class);
          }
          class_body
        ;
@@ -224,6 +253,7 @@ type_name
          {
                ValaTypeReference *type_reference = g_new0 (ValaTypeReference, 1);
                type_reference->type_name = g_strdup ($1);
+               type_reference->location = current_location (@1);
                $$ = type_reference;
          }
        | IDENTIFIER DOT IDENTIFIER
@@ -231,11 +261,123 @@ type_name
                ValaTypeReference *type_reference = g_new0 (ValaTypeReference, 1);
                type_reference->namespace_name = g_strdup ($1);
                type_reference->type_name = g_strdup ($3);
+               type_reference->location = current_location (@1);
                $$ = type_reference;
          }
        ;
 
 class_body
+       : OPEN_BRACE opt_class_member_declarations CLOSE_BRACE
+       ;
+
+opt_class_member_declarations
+       : /* empty */
+       | class_member_declarations
+       ;
+       
+class_member_declarations
+       : class_member_declaration
+       | class_member_declarations class_member_declaration
+       ;
+
+class_member_declaration
+       : method_declaration
+       ;
+
+method_declaration
+       : method_header method_body
+       ;
+
+method_header
+       : opt_method_modifiers type_name IDENTIFIER OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
+         {
+               current_method = g_new0 (ValaMethod, 1);
+               current_method->name = g_strdup ($3);
+               current_method->class = current_class;
+               current_method->return_type = $2;
+               current_method->formal_parameters = $5;
+               current_method->modifiers = $1;
+               current_method->location = current_location (@3);
+               
+               current_class->methods = g_list_append (current_class->methods, current_method);
+         }
+       ;
+
+opt_method_modifiers
+       : /* empty */
+         {
+               $$ = 0;
+         }
+       | method_modifiers
+         {
+               $$ = $1;
+         }
+       ;
+
+method_modifiers
+       : method_modifier
+         {
+               $$ = $1;
+         }
+       | method_modifiers method_modifier
+         {
+               $$ = $1 | $2;
+         }
+       ;
+
+method_modifier
+       : PUBLIC
+         {
+               $$ = VALA_METHOD_PUBLIC;
+         }
+       | STATIC
+         {
+               $$ = VALA_METHOD_STATIC;
+         }
+       ;
+
+opt_formal_parameter_list
+       : /* empty */
+         {
+               $$ = NULL;
+         }
+       | formal_parameter_list
+         {
+               $$ = $1;
+         }
+       ;
+
+formal_parameter_list
+       : fixed_parameters
+       ;
+
+fixed_parameters
+       : fixed_parameter
+         {
+               $$ = g_list_append (NULL, $1);
+         }
+       | fixed_parameters COMMA fixed_parameter
+         {
+               $$ = g_list_append ($1, $3);
+         }
+       ;
+
+fixed_parameter
+       : type_name IDENTIFIER
+         {
+               $$ = g_new0 (ValaFormalParameter, 1);
+               $$->type = $1;
+               $$->name = $2;
+               $$->location = current_location (@2);
+         }
+       ;
+
+method_body
+       : block
+       | SEMICOLON
+       ;
+
+block
        : OPEN_BRACE CLOSE_BRACE
        ;
 
@@ -245,7 +387,7 @@ extern FILE *yyin;
 
 void yyerror (YYLTYPE *locp, const char *s)
 {
-       printf ("%d: %s\n", locp->first_line, s);
+       printf ("%s:%d:%d-%d: %s\n", current_source_file->filename, locp->first_line, locp->first_column, locp->last_column, s);
 }
 
 void vala_parser_parse (ValaSourceFile *source_file)
index 1d2a636..0a41db5 100644 (file)
@@ -23,6 +23,8 @@
 %{
 #include "context.h"
 #include "parser.h"
+
+#define uploc  { yylloc->first_column = yylloc->last_column + 1; yylloc->last_column += strlen (yytext); }
 %}
  
 %option yylineno
 
 %%
 
-"{"            { return OPEN_BRACE; }
-"}"            { return CLOSE_BRACE; }
-"."            { return DOT; }
-":"            { return COLON; }
-","            { return COMMA; }
+"{"            { uploc; return OPEN_BRACE; }
+"}"            { uploc; return CLOSE_BRACE; }
+"("            { uploc; return OPEN_PARENS; }
+")"            { uploc; return CLOSE_PARENS; }
+"."            { uploc; return DOT; }
+":"            { uploc; return COLON; }
+","            { uploc; return COMMA; }
+";"            { uploc; return SEMICOLON; }
 
-"namespace"    { return NAMESPACE; }
-"class"                { return CLASS; }
+"namespace"    { uploc; return NAMESPACE; }
+"class"                { uploc; return CLASS; }
+"public"       { uploc; return PUBLIC; }
+"static"       { uploc; return STATIC; }
 
-[[:alnum:]_]+  { yylval->str = strdup (yytext); return IDENTIFIER; }
+[[:alnum:]_]+  { uploc; yylval->str = strdup (yytext); return IDENTIFIER; }
 
-[ \t\n]+ /* eat up whitespace */
+[ \t]+         { uploc; /* eat up whitespace */ }
+[\n]+          { yylloc->first_line = yylloc->last_line = yylineno; yylloc->first_column = 1; yylloc->last_column = 0; }