]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
support LAMBDA and CALLBACK support callbacks and lambda expressions add
authorJürg Billeter <j@bitron.ch>
Thu, 22 Jun 2006 08:48:18 +0000 (08:48 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Thu, 22 Jun 2006 08:48:18 +0000 (08:48 +0000)
2006-06-22  Jürg Billeter  <j@bitron.ch>

* vala/scanner.l: support LAMBDA and CALLBACK
* vala/parser.y: support callbacks and lambda expressions
* vala/valacodevisitor.vala: add visit methods for callbacks and lambda
  expressions
* vala/valasymbolbuilder.vala: use non-null parameter types, support
  callbacks
* vala/valasemanticanalyzer.vala: partially support interface methods,
  support callback invocations
* vala/valamemorymanager.vala: support callback invocations
* vala/valacodegenerator.vala: partially support interface methods
* vala/valacallback.vala: initial implementation
* vala/valacodenode.vala: replace public fields by properties
* vala/valaexpression.vala: add expected_type field
* vala/valainvocationexpression.vala: also visit at beginning
* vala/valalambdaexpression.vala
* vala/valanamespace.vala: support callbacks
* vala/vala.h: update
* vala/Makefile.am: update

svn path=/trunk/; revision=50

16 files changed:
vala/ChangeLog
vala/vala/Makefile.am
vala/vala/parser.y
vala/vala/scanner.l
vala/vala/vala.h
vala/vala/valacallback.vala
vala/vala/valacodegenerator.vala
vala/vala/valacodenode.vala
vala/vala/valacodevisitor.vala
vala/vala/valaexpression.vala
vala/vala/valainvocationexpression.vala
vala/vala/valalambdaexpression.vala [new file with mode: 0644]
vala/vala/valamemorymanager.vala
vala/vala/valanamespace.vala
vala/vala/valasemanticanalyzer.vala
vala/vala/valasymbolbuilder.vala

index 930b033d1af4fe4ef1f95b81e0c4d86d7ae38d09..e01979bdad06faba30b7af3675c73eddf54fcaba 100644 (file)
@@ -1,3 +1,24 @@
+2006-06-22  Jürg Billeter  <j@bitron.ch>
+
+       * vala/scanner.l: support LAMBDA and CALLBACK
+       * vala/parser.y: support callbacks and lambda expressions
+       * vala/valacodevisitor.vala: add visit methods for callbacks and lambda
+         expressions
+       * vala/valasymbolbuilder.vala: use non-null parameter types, support
+         callbacks
+       * vala/valasemanticanalyzer.vala: partially support interface methods,
+         support callback invocations
+       * vala/valamemorymanager.vala: support callback invocations
+       * vala/valacodegenerator.vala: partially support interface methods
+       * vala/valacallback.vala: initial implementation
+       * vala/valacodenode.vala: replace public fields by properties
+       * vala/valaexpression.vala: add expected_type field
+       * vala/valainvocationexpression.vala: also visit at beginning
+       * vala/valalambdaexpression.vala
+       * vala/valanamespace.vala: support callbacks
+       * vala/vala.h: update
+       * vala/Makefile.am: update
+
 2006-06-18  Jürg Billeter  <j@bitron.ch>
 
        * vala/scanner.l: support TYPEOF
index 53388cf3f9a71f318b419c3fbdc20b4330b7972c..0f466e8174378b91803243fbe136c7fa05c3c9f9 100644 (file)
@@ -140,6 +140,9 @@ libvala_la_SOURCES = \
        valainvocationexpression.c \
        valainvocationexpression.h \
        valainvocationexpression.vala \
+       valalambdaexpression.c \
+       valalambdaexpression.h \
+       valalambdaexpression.vala \
        valaliteral.c \
        valaliteral.h \
        valaliteral.vala \
index 39b9ad79fcea286ca5392e62cbdc5101cd8b6e37..53e5385bbd728ac50ada8c20ca3653ad6c150eb8 100644 (file)
@@ -75,6 +75,7 @@ static void yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg);
        ValaEnumValue *enum_value;
        ValaFlags *flags;
        ValaFlagsValue *flags_value;
+       ValaCallback *callback;
        ValaConstant *constant;
        ValaField *field;
        ValaMethod *method;
@@ -125,6 +126,7 @@ static void yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg);
 %token OP_SHIFT_RIGHT ">>"
 %token OP_LE "<="
 %token OP_GE ">="
+%token LAMBDA "=>"
 %token GENERIC_LT "generic <"
 %token OP_LT "<"
 %token OP_GT ">"
@@ -145,6 +147,7 @@ static void yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg);
 
 %token ABSTRACT "abstract"
 %token BREAK "break"
+%token CALLBACK "callback"
 %token CLASS "class"
 %token CONST "const"
 %token CONSTRUCT "construct"
@@ -218,6 +221,9 @@ static void yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg);
 %type <expression> conditional_and_expression
 %type <expression> conditional_or_expression
 %type <expression> conditional_expression
+%type <expression> lambda_expression
+%type <list> opt_lambda_parameter_list
+%type <list> lambda_parameter_list
 %type <expression> assignment
 %type <num> assignment_operator
 %type <expression> opt_expression
@@ -275,6 +281,7 @@ static void yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg);
 %type <list> enum_member_declarations
 %type <enum_value> enum_member_declaration
 %type <flags> flags_declaration
+%type <callback> callback_declaration
 %type <constant> constant_declaration
 %type <variable_declarator> constant_declarator
 %type <field> field_declaration
@@ -853,6 +860,48 @@ conditional_expression
          }
        ;
 
+lambda_expression
+       : OPEN_PARENS opt_lambda_parameter_list CLOSE_PARENS LAMBDA expression
+         {
+               ValaSourceReference *src = src(@4);
+               $$ = VALA_EXPRESSION (vala_lambda_expression_new ($2, $5, src));
+               if ($2 != NULL) {
+                       g_list_free ($2);
+               }
+               g_object_unref ($5);
+               g_object_unref (src);
+         }
+       | IDENTIFIER LAMBDA expression
+         {
+               ValaSourceReference *src = src(@2);
+               $$ = VALA_EXPRESSION (vala_lambda_expression_new (NULL, $3, src));
+               g_object_unref ($3);
+               g_object_unref (src);
+               vala_lambda_expression_add_parameter (VALA_LAMBDA_EXPRESSION ($$), $1);
+               g_free ($1);
+         }
+       ;
+
+opt_lambda_parameter_list
+       : /* empty */
+         {
+               $$ = NULL;
+         }
+       | lambda_parameter_list
+       ;
+
+lambda_parameter_list
+       : IDENTIFIER COMMA IDENTIFIER
+         {
+               $$ = g_list_append (NULL, $1);
+               $$ = g_list_append ($$, $3);
+         }
+       | lambda_parameter_list COMMA IDENTIFIER
+         {
+               $$ = g_list_append ($1, $3);
+         }
+       ;
+
 assignment
        : unary_expression assignment_operator expression
          {
@@ -921,6 +970,7 @@ opt_expression
 
 expression
        : conditional_expression
+       | lambda_expression
        | assignment
        | error
          {
@@ -1319,6 +1369,14 @@ namespace_member_declaration
                        g_object_unref ($1);
                }
          }
+       | callback_declaration
+         {
+               /* skip declarations with errors */
+               if ($1 != NULL) {
+                       vala_namespace_add_callback (current_namespace, $1);
+                       g_object_unref ($1);
+               }
+         }
        | field_declaration
          {
                /* skip declarations with errors */
@@ -2221,6 +2279,32 @@ flags_member_declaration
        : opt_attributes IDENTIFIER
        ;
 
+callback_declaration
+       : comment opt_attributes opt_access_modifier CALLBACK type identifier_or_new OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS SEMICOLON
+         {
+               GList *l;
+               
+               ValaSourceReference *src = src_com(@6, $1);
+               $$ = vala_callback_new ($6, $5, src);
+               g_object_unref (src);
+               if ($3 != 0) {
+                       VALA_TYPE_($$)->access = $3;
+               }
+               VALA_CODE_NODE($$)->attributes = $2;
+               
+               for (l = $8; l != NULL; l = l->next) {
+                       vala_callback_add_parameter ($$, l->data);
+                       g_object_unref (l->data);
+               }
+               if ($8 != NULL) {
+                       g_list_free ($8);
+               }
+
+               g_object_unref ($5);
+               g_free ($6);
+         }
+       ;
+
 opt_attributes
        : /* empty */
          {
index c3fd7086a54d0c1edd2e266e88d0c0cf3b172509..d3b9b3e9d3592a1ea4da1fdabd2d8e975b33f6c3 100644 (file)
@@ -92,6 +92,7 @@ literal                       ({literal_integer}|{literal_real}|{literal_character}|{literal_string}
 ">>"           { uploc; return OP_SHIFT_RIGHT; }
 "<="           { uploc; return OP_LE; }
 ">="           { uploc; return OP_GE; }
+"=>"           { uploc; return LAMBDA; }
 "<"(("ref"|"weak")" "+)?({ident}".")?{ident}"#"?("[]""#"?)?(","" "*({ident}".")?{ident}"#"?("[]""#"?)?)*">"    { yyless (1); uploc; return GENERIC_LT; }
 "<"            { uploc; return OP_LT; }
 ">"            { uploc; return OP_GT; }
@@ -114,6 +115,7 @@ literal                     ({literal_integer}|{literal_real}|{literal_character}|{literal_string}
 
 "abstract"     { uploc; return ABSTRACT; }
 "break"                { uploc; return BREAK; }
+"callback"     { uploc; return CALLBACK; }
 "class"                { uploc; return CLASS; }
 "const"                { uploc; return CONST; }
 "construct"    { uploc; return CONSTRUCT; }
index 009001c9d82592434840a8f28ce5c4d72168d93b..88733b13b1570ac4d2a897d70791b0c08f0edb41 100644 (file)
@@ -4,6 +4,7 @@
 #include <vala/valablock.h>
 #include <vala/valabooleanliteral.h>
 #include <vala/valabreakstatement.h>
+#include <vala/valacallback.h>
 #include <vala/valacastexpression.h>
 #include <vala/valacharacterliteral.h>
 #include <vala/valaclass.h>
@@ -29,6 +30,7 @@
 #include <vala/valaintegerliteral.h>
 #include <vala/valainterface.h>
 #include <vala/valainvocationexpression.h>
+#include <vala/valalambdaexpression.h>
 #include <vala/valaliteral.h>
 #include <vala/valaliteralexpression.h>
 #include <vala/valalocalvariabledeclaration.h>
index 9cc73ac2215beaccf2c22371c2087c43c02dcdbc..0185c0533f19946f996a21267a8c9061a9cc0fc3 100644 (file)
@@ -24,5 +24,51 @@ using GLib;
 
 namespace Vala {
        public class Callback : Type_ {
+               public TypeReference return_type { get; construct; }
+               public List<FormalParameter> parameters;
+               
+               public static ref Callback new (string! name, TypeReference return_type, SourceReference source) {
+                       return (new Callback (name = name, return_type = return_type, source_reference = source));
+               }
+               
+               public void add_parameter (FormalParameter! param) {
+                       parameters.append (param);
+               }
+               
+               public ref List<FormalParameter> get_parameters () {
+                       return parameters.copy ();
+               }
+               
+               public override void accept (CodeVisitor! visitor) {
+                       visitor.visit_begin_callback (this);
+                       
+                       return_type.accept (visitor);
+                       
+                       foreach (FormalParameter param in parameters) {
+                               param.accept (visitor);
+                       }
+
+                       visitor.visit_end_callback (this);
+               }
+
+               private string cname;           
+               public override string get_cname () {
+                       if (cname == null) {
+                               cname = "%s%s".printf (@namespace.get_cprefix (), name);
+                       }
+                       return cname;
+               }
+
+               public override bool is_reference_type () {
+                       return true;
+               }
+               
+               public override string get_ref_function () {
+                       return "";
+               }
+               
+               public override string get_free_function () {
+                       return "";
+               }
        }
 }
index 9e6228207f79a287c2ac8eee02f595f0ec2e4ed9..70c7f2626c841cbbfdbcf21fdbf80b6ecffa853c 100644 (file)
@@ -302,7 +302,9 @@ namespace Vala {
                        var methods = cl.get_methods ();
                        foreach (Method m in methods) {
                                if (m.is_virtual || m.is_override) {
-                                       var ccast = new CCodeFunctionCall (call = new CCodeIdentifier (name = "%s_CLASS".printf (((Class) m.base_method.symbol.parent_symbol.node).get_upper_case_cname (null))));
+                                       var base_type = m.base_method.symbol.parent_symbol.node;
+                               
+                                       var ccast = new CCodeFunctionCall (call = new CCodeIdentifier (name = "%s_CLASS".printf (((Class) base_type).get_upper_case_cname (null))));
                                        ccast.add_argument (new CCodeIdentifier (name = "klass"));
                                        init_block.add_statement (new CCodeExpressionStatement (expression = new CCodeAssignment (left = new CCodeMemberAccess (inner = ccast, member_name = m.name, is_pointer = true), right = new CCodeIdentifier (name = m.get_real_cname ()))));
                                }
@@ -695,7 +697,7 @@ namespace Vala {
                                        function.add_parameter (cparam);
                                } else {
                                        var base_type = new TypeReference ();
-                                       base_type.type = (Class) m.base_method.symbol.parent_symbol.node;
+                                       base_type.type = (Type_) m.base_method.symbol.parent_symbol.node;
                                        var cparam = new CCodeFormalParameter (type_name = base_type.get_cname (), name = "base");
                                        function.add_parameter (cparam);
                                }
@@ -1497,7 +1499,7 @@ namespace Vala {
                        visit_expression (expr);
                }
 
-               public override void visit_invocation_expression (InvocationExpression! expr) {
+               public override void visit_end_invocation_expression (InvocationExpression! expr) {
                        var ccall = new CCodeFunctionCall (call = (CCodeExpression) expr.call.ccodenode);
                        
                        var m = (Method) expr.call.symbol_reference.node;
index a194caa6e3dd5764d6dd2f6bf6edf8840d952d7a..93aa1d9636be67d9f0ee9ae1e5ff87faf6a71d2a 100644 (file)
@@ -24,10 +24,10 @@ using GLib;
 
 namespace Vala {
        public abstract class CodeNode {
-               public Symbol symbol;
+               public Symbol symbol { get; set; }
                public List<Attribute> attributes;
-               public CCodeNode ccodenode;
-               public bool error;
+               public CCodeNode ccodenode { get; set; }
+               public bool error { get; set; }
        
                public abstract void accept (CodeVisitor visitor);
        }
index 7e568e89258eb0736e8622d33b53d26be844f8b3..cf773a97e29044eb59576b3560ee55ba805720f1 100644 (file)
@@ -72,6 +72,12 @@ namespace Vala {
                public virtual void visit_flags_value (FlagsValue! fv) {
                }
 
+               public virtual void visit_begin_callback (Callback! cb) {
+               }
+
+               public virtual void visit_end_callback (Callback! cb) {
+               }
+
                public virtual void visit_constant (Constant! c) {
                }
 
@@ -207,7 +213,10 @@ namespace Vala {
                public virtual void visit_member_access (MemberAccess! expr) {
                }
 
-               public virtual void visit_invocation_expression (InvocationExpression! expr) {
+               public virtual void visit_begin_invocation_expression (InvocationExpression! expr) {
+               }
+
+               public virtual void visit_end_invocation_expression (InvocationExpression! expr) {
                }
 
                public virtual void visit_postfix_expression (PostfixExpression! expr) {
@@ -234,6 +243,12 @@ namespace Vala {
                public virtual void visit_conditional_expression (ConditionalExpression! expr) {
                }
 
+               public virtual void visit_begin_lambda_expression (LambdaExpression! expr) {
+               }
+
+               public virtual void visit_end_lambda_expression (LambdaExpression! expr) {
+               }
+
                public virtual void visit_assignment (Assignment! a) {
                }
 
index 7f51b2978a9837700716d5fa6d8c6fe70f52fee6..736da20eb166581e3a08e44e72da53e0d2b3f5a9 100644 (file)
@@ -31,6 +31,11 @@ namespace Vala {
                 */
                public TypeReference static_type;
                
+               /* filled by semantic analyzer, used by lambda expressions in
+                * semantic analyzer
+                */
+               public TypeReference expected_type;
+               
                public Symbol symbol_reference;
                
                /* set by memory manager, used by code generator */
index 1ed19432c668d3255a7d7f2c8544f9c8a093750e..4f1bb1ce6ea026da3f43d6064ee017425ea624b8 100644 (file)
@@ -36,12 +36,14 @@ namespace Vala {
                }
                
                public override void accept (CodeVisitor visitor) {
+                       visitor.visit_begin_invocation_expression (this);
+
                        call.accept (visitor);
                        foreach (Expression expr in argument_list) {
                                expr.accept (visitor);
                        }
 
-                       visitor.visit_invocation_expression (this);
+                       visitor.visit_end_invocation_expression (this);
                }
        }
 }
diff --git a/vala/vala/valalambdaexpression.vala b/vala/vala/valalambdaexpression.vala
new file mode 100644 (file)
index 0000000..ee46855
--- /dev/null
@@ -0,0 +1,54 @@
+/* valalambdaexpression.vala
+ *
+ * Copyright (C) 2006  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+using GLib;
+
+namespace Vala {
+       public class LambdaExpression : Expression {
+               public List<string> parameters { get; set; }
+               public Expression inner { get; set; }
+               
+               /* generated anonymous method */
+               public Method method;
+               
+               public static ref LambdaExpression new (List<String> params, Expression! inner, SourceReference source) {
+                       return new LambdaExpression (parameters = params, inner = inner, source_reference = source);
+               }
+               
+               public void add_parameter (string! param) {
+                       _parameters.append (param);
+               }
+               
+               public override void accept (CodeVisitor! visitor) {
+                       visitor.visit_begin_lambda_expression (this);
+
+                       inner.accept (visitor);
+                       visitor.visit_end_full_expression (inner);
+
+                       visitor.visit_end_lambda_expression (this);
+                       
+                       if (method != null) {
+                               method.accept (visitor);
+                       }
+               }
+       }
+}
index 0d2cf7d320487006e67664cf4fad7545164c55ae..ff3ad696fc1609a1fcb4209dd91089f06715ca14 100644 (file)
@@ -95,9 +95,17 @@ namespace Vala {
                        visit_possibly_leaked_expression (expr.inner);
                }
 
-               public override void visit_invocation_expression (InvocationExpression! expr) {
-                       var m = (Method) expr.call.symbol_reference.node;
-                       var params = m.get_parameters ();
+               public override void visit_end_invocation_expression (InvocationExpression! expr) {
+                       List<FormalParameter> params;
+                       
+                       var msym = expr.call.symbol_reference;
+                       if (msym.node is Callback) {
+                               var cb = (Callback) msym.node;
+                               params = cb.get_parameters ();
+                       } else {
+                               var m = (Method) msym.node;
+                               params = m.get_parameters ();
+                       }
                        foreach (Expression arg in expr.argument_list) {
                                if (params != null) {
                                        var param = (FormalParameter) params.data;
index 56a8a6f55169a3076af94ecf51a0667f197f7f2f..630b0e3fa4aff503900ee181adf6e8dbb7cc12ef 100644 (file)
@@ -32,6 +32,7 @@ namespace Vala {
                List<Struct> structs;
                List<Enum> enums;
                List<Flags> flags_;
+               List<Callback> callbacks;
                List<Field> fields;
                List<Method> methods;
                
@@ -76,6 +77,11 @@ namespace Vala {
                        flags_.append (fl);
                        fl.@namespace = this;
                }
+                               
+               public void add_callback (Callback! cb) {
+                       callbacks.append (cb);
+                       cb.@namespace = this;
+               }
 
                public ref List<Struct> get_structs () {
                        return structs.copy ();
@@ -116,6 +122,10 @@ namespace Vala {
                                fl.accept (visitor);
                        }
 
+                       foreach (Callback cb in callbacks) {
+                               cb.accept (visitor);
+                       }
+
                        foreach (Field f in fields) {
                                f.accept (visitor);
                        }
index e2b044c3d7d43bc999495cfbd4982172cff93ccf..4a492145b37f8c12f7c4cccdd00aa8769ef7e700 100644 (file)
@@ -130,6 +130,24 @@ namespace Vala {
                                                        }
                                                }
                                        }
+                                       if (m.base_method == null) {
+                                               /* FIXME: also look at interfaces implemented
+                                                * by one of the base types
+                                                */
+                                               foreach (TypeReference type in cl.base_types) {
+                                                       if (type.type is Interface) {
+                                                               var iface = (Interface) type.type;
+                                                               var sym = iface.symbol.lookup (m.name);
+                                                               if (sym != null && sym.node is Method) {
+                                                                       var base_method = (Method) sym.node;
+                                                                       if (base_method.is_abstract || base_method.is_virtual) {
+                                                                               m.base_method = base_method;
+                                                                               break;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
                                        if (m.base_method == null) {
                                                Report.error (m.source_reference, "%s: no suitable method found to override".printf (m.symbol.get_full_name ()));
                                        }
@@ -444,20 +462,37 @@ namespace Vala {
                        return false;
                }
 
-               public override void visit_invocation_expression (InvocationExpression! expr) {
+               public override void visit_begin_invocation_expression (InvocationExpression! expr) {
+               }
+
+               public override void visit_end_invocation_expression (InvocationExpression! expr) {
                        if (expr.call.symbol_reference == null) {
                                /* if method resolving didn't succeed, skip this check */
                                return;
                        }
+                       
+                       var msym = expr.call.symbol_reference;
+                       
+                       TypeReference ret_type;
+                       List<FormalParameter> params;
+                       
+                       if (msym.node is Callback) {
+                               var cb = (Callback) msym.node;
+                               ret_type = cb.return_type;
+                               params = cb.parameters;
+                       } else {
+                               var m = (Method) msym.node;
+                               ret_type = m.return_type;
+                               params = m.parameters;
+                       }
                
-                       var m = (Method) expr.call.symbol_reference.node;
-                       expr.static_type = m.return_type;
+                       expr.static_type = ret_type;
                        
                        List arg_it = expr.argument_list;
                        
                        bool ellipsis = false;
                        int i = 0;
-                       foreach (FormalParameter param in m.parameters) {
+                       foreach (FormalParameter param in params) {
                                if (param.ellipsis) {
                                        ellipsis = true;
                                        break;
@@ -470,7 +505,7 @@ namespace Vala {
 
                                if (arg_it == null) {
                                        if (param.default_expression == null) {
-                                               Report.error (expr.source_reference, "Method `%s' does not take %d arguments".printf (m.symbol.get_full_name (), expr.argument_list.length ()));
+                                               Report.error (expr.source_reference, "Method `%s' does not take %d arguments".printf (msym.get_full_name (), expr.argument_list.length ()));
                                                return;
                                        }
                                } else {
@@ -489,7 +524,7 @@ namespace Vala {
                        }
                        
                        if (!ellipsis && arg_it != null) {
-                               Report.error (expr.source_reference, "Method `%s' does not take %d arguments".printf (m.symbol.get_full_name (), expr.argument_list.length ()));
+                               Report.error (expr.source_reference, "Method `%s' does not take %d arguments".printf (msym.get_full_name (), expr.argument_list.length ()));
                                return;
                        }
                }
index 908c6c0fe60da6ef474305daa72689aab08854b0..752b48c60045ee9b623d463007274f7436b65bec 100644 (file)
@@ -29,12 +29,12 @@ namespace Vala {
                Symbol current_type;
                Symbol current_symbol;
                
-               public void build (CodeContext context) {
+               public void build (CodeContext! context) {
                        root = context.root;
                        context.accept (this);
                }
                
-               public override void visit_begin_namespace (Namespace ns) {
+               public override void visit_begin_namespace (Namespace! ns) {
                        if (ns.name == null) {
                                ns.symbol = root;
                                return;
@@ -48,11 +48,11 @@ namespace Vala {
                        current_symbol = ns.symbol;
                }
                
-               public override void visit_end_namespace (Namespace ns) {
+               public override void visit_end_namespace (Namespace! ns) {
                        current_symbol = current_symbol.parent_symbol;
                }
        
-               public override void visit_begin_class (Class cl) {
+               public override void visit_begin_class (Class! cl) {
                        if (cl.@namespace.symbol.lookup (cl.name) != null) {
                                cl.error = true;
                                Report.error (cl.source_reference, "The namespace `%s' already contains a definition for `%s'".printf (cl.@namespace.symbol.get_full_name (), cl.name));
@@ -64,7 +64,7 @@ namespace Vala {
                        current_symbol = cl.symbol;
                }
                
-               public override void visit_end_class (Class cl) {
+               public override void visit_end_class (Class! cl) {
                        if (cl.error) {
                                /* skip classes with errors */
                                return;
@@ -73,7 +73,7 @@ namespace Vala {
                        current_symbol = current_symbol.parent_symbol;
                }
                
-               public override void visit_begin_struct (Struct st) {
+               public override void visit_begin_struct (Struct! st) {
                        if (st.@namespace.symbol.lookup (st.name) != null) {
                                st.error = true;
                                Report.error (st.source_reference, "The namespace `%s' already contains a definition for `%s'".printf (st.@namespace.symbol.get_full_name (), st.name));
@@ -85,7 +85,7 @@ namespace Vala {
                        current_symbol = st.symbol;
                }
                
-               public override void visit_end_struct (Struct st) {
+               public override void visit_end_struct (Struct! st) {
                        if (st.error) {
                                /* skip structs with errors */
                                return;
@@ -94,7 +94,7 @@ namespace Vala {
                        current_symbol = current_symbol.parent_symbol;
                }
        
-               public override void visit_begin_interface (Interface iface) {
+               public override void visit_begin_interface (Interface! iface) {
                        if (iface.@namespace.symbol.lookup (iface.name) != null) {
                                iface.error = true;
                                Report.error (iface.source_reference, "The namespace `%s' already contains a definition for `%s'".printf (iface.@namespace.symbol.get_full_name (), iface.name));
@@ -106,7 +106,7 @@ namespace Vala {
                        current_symbol = iface.symbol;
                }
                
-               public override void visit_end_interface (Interface iface) {
+               public override void visit_end_interface (Interface! iface) {
                        if (iface.error) {
                                /* skip interfaces with errors */
                                return;
@@ -115,7 +115,7 @@ namespace Vala {
                        current_symbol = current_symbol.parent_symbol;
                }
                
-               public override void visit_begin_enum (Enum en) {
+               public override void visit_begin_enum (Enum! en) {
                        if (en.@namespace.symbol.lookup (en.name) != null) {
                                en.error = true;
                                Report.error (en.source_reference, "The namespace `%s' already contains a definition for `%s'".printf (en.@namespace.symbol.get_full_name (), en.name));
@@ -126,7 +126,7 @@ namespace Vala {
                        current_symbol = en.symbol;
                }
                
-               public override void visit_end_enum (Enum en) {
+               public override void visit_end_enum (Enum! en) {
                        if (en.error) {
                                /* skip enums with errors */
                                return;
@@ -135,12 +135,32 @@ namespace Vala {
                        current_symbol = current_symbol.parent_symbol;
                }
 
-               public override void visit_enum_value (EnumValue ev) {
+               public override void visit_enum_value (EnumValue! ev) {
                        ev.symbol = new Symbol (node = ev);
                        current_symbol.add (ev.name, ev.symbol);
                }
+               
+               public override void visit_begin_callback (Callback! cb) {
+                       if (cb.@namespace.symbol.lookup (cb.name) != null) {
+                               cb.error = true;
+                               Report.error (cb.source_reference, "The namespace `%s' already contains a definition for `%s'".printf (cb.@namespace.symbol.get_full_name (), cb.name));
+                               return;
+                       }
+                       cb.symbol = new Symbol (node = cb);
+                       cb.@namespace.symbol.add (cb.name, cb.symbol);
+                       current_symbol = cb.symbol;
+               }
+               
+               public override void visit_end_callback (Callback! cb) {
+                       if (cb.error) {
+                               /* skip enums with errors */
+                               return;
+                       }
+                       
+                       current_symbol = current_symbol.parent_symbol;
+               }
 
-               public override void visit_constant (Constant c) {
+               public override void visit_constant (Constant! c) {
                        if (current_symbol.lookup (c.name) != null) {
                                c.error = true;
                                Report.error (c.source_reference, "The type `%s' already contains a definition for `%s'".printf (current_symbol.get_full_name (), c.name));
@@ -150,7 +170,7 @@ namespace Vala {
                        current_symbol.add (c.name, c.symbol);
                }
                
-               public override void visit_field (Field f) {
+               public override void visit_field (Field! f) {
                        if (current_symbol.lookup (f.name) != null) {
                                f.error = true;
                                Report.error (f.source_reference, "The type `%s' already contains a definition for `%s'".printf (current_symbol.get_full_name (), f.name));
@@ -160,7 +180,7 @@ namespace Vala {
                        current_symbol.add (f.name, f.symbol);
                }
                
-               public override void visit_begin_method (Method m) {
+               public override void visit_begin_method (Method! m) {
                        if (current_symbol.lookup (m.name) != null) {
                                m.error = true;
                                Report.error (m.source_reference, "The type `%s' already contains a definition for `%s'".printf (current_symbol.get_full_name (), m.name));
@@ -178,7 +198,7 @@ namespace Vala {
                        }
                }
                
-               public override void visit_end_method (Method m) {
+               public override void visit_end_method (Method! m) {
                        if (m.error) {
                                /* skip methods with errors */
                                return;
@@ -187,14 +207,14 @@ namespace Vala {
                        current_symbol = current_symbol.parent_symbol;
                }
 
-               public override void visit_formal_parameter (FormalParameter p) {
+               public override void visit_formal_parameter (FormalParameter! p) {
                        if (!p.ellipsis) {
                                p.symbol = new Symbol (node = p);
                                current_symbol.add (p.name, p.symbol);
                        }
                }
                
-               public override void visit_begin_property (Property prop) {
+               public override void visit_begin_property (Property! prop) {
                        if (current_symbol.lookup (prop.name) != null) {
                                prop.error = true;
                                Report.error (prop.source_reference, "The type `%s' already contains a definition for `%s'".printf (current_symbol.get_full_name (), prop.name));
@@ -210,7 +230,7 @@ namespace Vala {
                        current_symbol.add (prop.this_parameter.name, prop.this_parameter.symbol);
                }
                
-               public override void visit_end_property (Property prop) {
+               public override void visit_end_property (Property! prop) {
                        if (prop.error) {
                                /* skip properties with errors */
                                return;
@@ -219,7 +239,7 @@ namespace Vala {
                        current_symbol = current_symbol.parent_symbol;
                }
                
-               public override void visit_begin_property_accessor (PropertyAccessor acc) {
+               public override void visit_begin_property_accessor (PropertyAccessor! acc) {
                        acc.symbol = new Symbol (node = acc);
                        acc.symbol.parent_symbol = current_symbol;
                        current_symbol = acc.symbol;
@@ -246,11 +266,11 @@ namespace Vala {
                        }
                }
                
-               public override void visit_end_property_accessor (PropertyAccessor acc) {
+               public override void visit_end_property_accessor (PropertyAccessor! acc) {
                        current_symbol = current_symbol.parent_symbol;
                }
 
-               public override void visit_begin_signal (Signal sig) {
+               public override void visit_begin_signal (Signal! sig) {
                        if (current_symbol.lookup (sig.name) != null) {
                                sig.error = true;
                                Report.error (sig.source_reference, "The type `%s' already contains a definition for `%s'".printf (current_symbol.get_full_name (), sig.name));
@@ -261,7 +281,7 @@ namespace Vala {
                        current_symbol = sig.symbol;
                }
 
-               public override void visit_end_signal (Signal sig) {
+               public override void visit_end_signal (Signal! sig) {
                        if (sig.error) {
                                /* skip signals with errors */
                                return;
@@ -270,37 +290,37 @@ namespace Vala {
                        current_symbol = current_symbol.parent_symbol;
                }
 
-               public override void visit_begin_constructor (Constructor c) {
+               public override void visit_begin_constructor (Constructor! c) {
                        c.symbol = new Symbol (node = c);
                        c.symbol.parent_symbol = current_symbol;
                        current_symbol = c.symbol;
                }
 
-               public override void visit_end_constructor (Constructor c) {
+               public override void visit_end_constructor (Constructor! c) {
                        current_symbol = current_symbol.parent_symbol;
                }
 
-               public override void visit_begin_destructor (Destructor d) {
+               public override void visit_begin_destructor (Destructor! d) {
                        d.symbol = new Symbol (node = d);
                        d.symbol.parent_symbol = current_symbol;
                        current_symbol = d.symbol;
                }
 
-               public override void visit_end_destructor (Destructor d) {
+               public override void visit_end_destructor (Destructor! d) {
                        current_symbol = current_symbol.parent_symbol;
                }
 
-               public override void visit_begin_block (Block b) {
+               public override void visit_begin_block (Block! b) {
                        b.symbol = new Symbol (node = b);
                        b.symbol.parent_symbol = current_symbol;
                        current_symbol = b.symbol;
                }
 
-               public override void visit_end_block (Block b) {
+               public override void visit_end_block (Block! b) {
                        current_symbol = current_symbol.parent_symbol;
                }
                
-               public override void visit_type_parameter (TypeParameter p) {
+               public override void visit_type_parameter (TypeParameter! p) {
                        if (p.type.symbol.lookup (p.name) != null) {
                                Report.error (p.source_reference, "The method `%s' already has a parameter named `%s'".printf (current_symbol.get_full_name (), p.name));
                                return;