>From 6c101e3de51675265e064453acf46f99b68e102c Mon Sep 17 00:00:00 2001 From: Philip Van Hoof <philip codeminded be> Date: Mon, 14 Oct 2013 17:41:17 +0200 Subject: [PATCH] Adds support for simple extension methods For the moment you can't use the parameter's identifier in the method, you must use this (which isn't correct yet). --- tests/Makefile.am | 1 + tests/methods/extensionmethods.vala | 32 ++++++++++++++++++++++++++++++++ vala/valamethod.vala | 2 ++ vala/valanamespace.vala | 15 +++++++++++++++ vala/valaparser.vala | 16 +++++++++++++++- 5 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 tests/methods/extensionmethods.vala diff --git a/tests/Makefile.am b/tests/Makefile.am index de7e823..5b88123 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -57,6 +57,7 @@ TESTS = \ methods/bug653908.vala \ methods/bug663210.vala \ methods/generics.vala \ + methods/extensionmethods.vala \ control-flow/break.vala \ control-flow/expressions-conditional.vala \ control-flow/for.vala \ diff --git a/tests/methods/extensionmethods.vala b/tests/methods/extensionmethods.vala new file mode 100644 index 0000000..073a8de --- /dev/null +++ b/tests/methods/extensionmethods.vala @@ -0,0 +1,32 @@ + +public class TestB +{ + public void Hello() { + print ("Hello\n"); + } +} + +public class TestA +{ + public void Test(TestB b) { + b.Hello(); + } +} + +public void Hallo(this TestA a, string msg) +{ + print ("Hallo %s\n", msg); + TestB b = new TestB(); + this.Test(b); +} + +public class Program { + static void main () + { + TestA a = new TestA(); + TestB b = new TestB(); + a.Test(b); + a.Hallo("hihi"); + + } +} diff --git a/vala/valamethod.vala b/vala/valamethod.vala index 663ae6f..3b5df12 100644 --- a/vala/valamethod.vala +++ b/vala/valamethod.vala @@ -41,6 +41,8 @@ public class Vala.Method : Subroutine { } } + public Parameter extension_for { get; set; } + public override bool has_result { get { return !(return_type is VoidType); } } diff --git a/vala/valanamespace.vala b/vala/valanamespace.vala index 47dd4ee..d8d6770 100644 --- a/vala/valanamespace.vala +++ b/vala/valanamespace.vala @@ -54,6 +54,21 @@ public class Vala.Namespace : Symbol { access = SymbolAccessibility.PUBLIC; } + public Class? find_in_tree (string f_name) { + foreach (Class cl in classes) { + if (cl.name == f_name) + return cl; + } + foreach (Namespace ns in namespaces) { + foreach (Class cl in ns.classes) { + if (cl.name == f_name) + return cl; + } + return ns.find_in_tree (f_name); + } + return null; + } + /** * Adds a new using directive with the specified namespace. * diff --git a/vala/valaparser.vala b/vala/valaparser.vala index a7ca9c0..22e708c 100644 --- a/vala/valaparser.vala +++ b/vala/valaparser.vala @@ -2615,6 +2615,10 @@ public class Vala.Parser : CodeVisitor { expect (TokenType.OPEN_PARENS); if (current () != TokenType.CLOSE_PARENS) { do { + if (accept (TokenType.THIS)) { + method.extension_for = parse_parameter (); + continue; + } var param = parse_parameter (); method.add_parameter (param); } while (accept (TokenType.COMMA)); @@ -2641,7 +2645,16 @@ public class Vala.Parser : CodeVisitor { method.external = true; } - parent.add_method (method); + if (method.extension_for != null) { + var cl = context.root.find_in_tree (method.extension_for.variable_type.to_string()); + if (cl != null) { + cl.add_method (method); + } else { + throw new ParseError.SYNTAX (get_error ("Could not find class `%s' to add extension method `%s' to".printf(method.extension_for.variable_type.to_string(), method.name))); + } + } else { + parent.add_method (method); + } } void parse_property_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError { @@ -3181,6 +3194,7 @@ public class Vala.Parser : CodeVisitor { if (accept (TokenType.ASSIGN)) { param.initializer = parse_expression (); } + return param; } -- 1.8.4.rc3