[vala/wip/issue/370] parser: Improve partial classes support




commit 73cd47c7c474d4601766a10e413e4e7512b810f2
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Sat Dec 18 22:25:54 2021 +0100

    parser: Improve partial classes support
    
    Fixes https://gitlab.gnome.org/GNOME/vala/issues/370

 tests/Makefile.am                             |   1 +
 tests/objects/class-partial-nested.c-expected | 440 ++++++++++++++++++++++++++
 tests/objects/class-partial-nested.vala       |  34 ++
 tests/objects/class-partial.c-expected        | 120 +++----
 vala/valaparser.vala                          |  69 +++-
 5 files changed, 601 insertions(+), 63 deletions(-)
---
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b3e51dc7b..788d9e474 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -471,6 +471,7 @@ TESTS = \
        objects/class-partial-conflict-access.test \
        objects/class-partial-conflict-partial.test \
        objects/class-partial-conflict-sealed.test \
+       objects/class-partial-nested.vala \
        objects/class-vfunc-base-access.vala \
        objects/classes.vala \
        objects/classes-interfaces.vala \
diff --git a/tests/objects/class-partial-nested.c-expected b/tests/objects/class-partial-nested.c-expected
new file mode 100644
index 000000000..32b00c14e
--- /dev/null
+++ b/tests/objects/class-partial-nested.c-expected
@@ -0,0 +1,440 @@
+/* objects_class_partial_nested.c generated by valac, the Vala compiler
+ * generated from objects_class_partial_nested.vala, do not modify */
+
+#include <glib-object.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <gobject/gvaluecollector.h>
+
+#if !defined(VALA_EXTERN)
+#if defined(_MSC_VER)
+#define VALA_EXTERN __declspec(dllexport) extern
+#elif __GNUC__ >= 4
+#define VALA_EXTERN __attribute__((visibility("default"))) extern
+#else
+#define VALA_EXTERN extern
+#endif
+#endif
+
+#define MANAM_FOO_BAR_TYPE_BAZ (manam_foo_bar_baz_get_type ())
+#define MANAM_FOO_BAR_BAZ(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MANAM_FOO_BAR_TYPE_BAZ, ManamFooBarBaz))
+#define MANAM_FOO_BAR_BAZ_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MANAM_FOO_BAR_TYPE_BAZ, 
ManamFooBarBazClass))
+#define MANAM_FOO_BAR_IS_BAZ(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MANAM_FOO_BAR_TYPE_BAZ))
+#define MANAM_FOO_BAR_IS_BAZ_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MANAM_FOO_BAR_TYPE_BAZ))
+#define MANAM_FOO_BAR_BAZ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MANAM_FOO_BAR_TYPE_BAZ, 
ManamFooBarBazClass))
+
+typedef struct _ManamFooBarBaz ManamFooBarBaz;
+typedef struct _ManamFooBarBazClass ManamFooBarBazClass;
+typedef struct _ManamFooBarBazPrivate ManamFooBarBazPrivate;
+#define _g_free0(var) (var = (g_free (var), NULL))
+#define _manam_foo_bar_baz_unref0(var) ((var == NULL) ? NULL : (var = (manam_foo_bar_baz_unref (var), NULL)))
+typedef struct _ManamFooBarParamSpecBaz ManamFooBarParamSpecBaz;
+
+struct _ManamFooBarBaz {
+       GTypeInstance parent_instance;
+       volatile int ref_count;
+       ManamFooBarBazPrivate * priv;
+       gchar* f0;
+       gchar* f1;
+};
+
+struct _ManamFooBarBazClass {
+       GTypeClass parent_class;
+       void (*finalize) (ManamFooBarBaz *self);
+       void (*v0) (ManamFooBarBaz* self);
+       void (*v1) (ManamFooBarBaz* self);
+};
+
+struct _ManamFooBarBazPrivate {
+       gchar* _p0;
+       gchar* _p1;
+};
+
+struct _ManamFooBarParamSpecBaz {
+       GParamSpec parent_instance;
+};
+
+static gint ManamFooBarBaz_private_offset;
+static gpointer manam_foo_bar_baz_parent_class = NULL;
+
+static void _vala_main (void);
+VALA_EXTERN gpointer manam_foo_bar_baz_ref (gpointer instance);
+VALA_EXTERN void manam_foo_bar_baz_unref (gpointer instance);
+VALA_EXTERN GParamSpec* manam_foo_bar_param_spec_baz (const gchar* name,
+                                          const gchar* nick,
+                                          const gchar* blurb,
+                                          GType object_type,
+                                          GParamFlags flags);
+VALA_EXTERN void manam_foo_bar_value_set_baz (GValue* value,
+                                  gpointer v_object);
+VALA_EXTERN void manam_foo_bar_value_take_baz (GValue* value,
+                                   gpointer v_object);
+VALA_EXTERN gpointer manam_foo_bar_value_get_baz (const GValue* value);
+VALA_EXTERN GType manam_foo_bar_baz_get_type (void) G_GNUC_CONST ;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (ManamFooBarBaz, manam_foo_bar_baz_unref)
+VALA_EXTERN ManamFooBarBaz* manam_foo_bar_baz_new (void);
+VALA_EXTERN ManamFooBarBaz* manam_foo_bar_baz_construct (GType object_type);
+VALA_EXTERN void manam_foo_bar_baz_set_p0 (ManamFooBarBaz* self,
+                               const gchar* value);
+VALA_EXTERN void manam_foo_bar_baz_m0 (ManamFooBarBaz* self);
+VALA_EXTERN void manam_foo_bar_baz_v0 (ManamFooBarBaz* self);
+VALA_EXTERN void manam_foo_bar_baz_set_p1 (ManamFooBarBaz* self,
+                               const gchar* value);
+VALA_EXTERN void manam_foo_bar_baz_m1 (ManamFooBarBaz* self);
+VALA_EXTERN void manam_foo_bar_baz_v1 (ManamFooBarBaz* self);
+static void manam_foo_bar_baz_real_v0 (ManamFooBarBaz* self);
+static void manam_foo_bar_baz_real_v1 (ManamFooBarBaz* self);
+VALA_EXTERN const gchar* manam_foo_bar_baz_get_p0 (ManamFooBarBaz* self);
+VALA_EXTERN const gchar* manam_foo_bar_baz_get_p1 (ManamFooBarBaz* self);
+static void manam_foo_bar_baz_finalize (ManamFooBarBaz * obj);
+static GType manam_foo_bar_baz_get_type_once (void);
+
+static void
+_vala_main (void)
+{
+       ManamFooBarBaz* baz = NULL;
+       ManamFooBarBaz* _tmp0_;
+       gchar* _tmp1_;
+       gchar* _tmp2_;
+       _tmp0_ = manam_foo_bar_baz_new ();
+       baz = _tmp0_;
+       manam_foo_bar_baz_set_p0 (baz, "p0");
+       _tmp1_ = g_strdup ("f0");
+       _g_free0 (baz->f0);
+       baz->f0 = _tmp1_;
+       manam_foo_bar_baz_m0 (baz);
+       manam_foo_bar_baz_v0 (baz);
+       manam_foo_bar_baz_set_p1 (baz, "p1");
+       _tmp2_ = g_strdup ("f1");
+       _g_free0 (baz->f1);
+       baz->f1 = _tmp2_;
+       manam_foo_bar_baz_m1 (baz);
+       manam_foo_bar_baz_v1 (baz);
+       _manam_foo_bar_baz_unref0 (baz);
+}
+
+int
+main (int argc,
+      char ** argv)
+{
+       _vala_main ();
+       return 0;
+}
+
+static inline gpointer
+manam_foo_bar_baz_get_instance_private (ManamFooBarBaz* self)
+{
+       return G_STRUCT_MEMBER_P (self, ManamFooBarBaz_private_offset);
+}
+
+void
+manam_foo_bar_baz_m0 (ManamFooBarBaz* self)
+{
+       g_return_if_fail (MANAM_FOO_BAR_IS_BAZ (self));
+}
+
+static void
+manam_foo_bar_baz_real_v0 (ManamFooBarBaz* self)
+{
+}
+
+void
+manam_foo_bar_baz_v0 (ManamFooBarBaz* self)
+{
+       ManamFooBarBazClass* _klass_;
+       g_return_if_fail (MANAM_FOO_BAR_IS_BAZ (self));
+       _klass_ = MANAM_FOO_BAR_BAZ_GET_CLASS (self);
+       if (_klass_->v0) {
+               _klass_->v0 (self);
+       }
+}
+
+ManamFooBarBaz*
+manam_foo_bar_baz_construct (GType object_type)
+{
+       ManamFooBarBaz* self = NULL;
+       self = (ManamFooBarBaz*) g_type_create_instance (object_type);
+       return self;
+}
+
+ManamFooBarBaz*
+manam_foo_bar_baz_new (void)
+{
+       return manam_foo_bar_baz_construct (MANAM_FOO_BAR_TYPE_BAZ);
+}
+
+void
+manam_foo_bar_baz_m1 (ManamFooBarBaz* self)
+{
+       g_return_if_fail (MANAM_FOO_BAR_IS_BAZ (self));
+}
+
+static void
+manam_foo_bar_baz_real_v1 (ManamFooBarBaz* self)
+{
+}
+
+void
+manam_foo_bar_baz_v1 (ManamFooBarBaz* self)
+{
+       ManamFooBarBazClass* _klass_;
+       g_return_if_fail (MANAM_FOO_BAR_IS_BAZ (self));
+       _klass_ = MANAM_FOO_BAR_BAZ_GET_CLASS (self);
+       if (_klass_->v1) {
+               _klass_->v1 (self);
+       }
+}
+
+const gchar*
+manam_foo_bar_baz_get_p0 (ManamFooBarBaz* self)
+{
+       const gchar* result;
+       const gchar* _tmp0_;
+       g_return_val_if_fail (MANAM_FOO_BAR_IS_BAZ (self), NULL);
+       _tmp0_ = self->priv->_p0;
+       result = _tmp0_;
+       return result;
+}
+
+void
+manam_foo_bar_baz_set_p0 (ManamFooBarBaz* self,
+                          const gchar* value)
+{
+       gchar* _tmp0_;
+       g_return_if_fail (MANAM_FOO_BAR_IS_BAZ (self));
+       _tmp0_ = g_strdup (value);
+       _g_free0 (self->priv->_p0);
+       self->priv->_p0 = _tmp0_;
+}
+
+const gchar*
+manam_foo_bar_baz_get_p1 (ManamFooBarBaz* self)
+{
+       const gchar* result;
+       const gchar* _tmp0_;
+       g_return_val_if_fail (MANAM_FOO_BAR_IS_BAZ (self), NULL);
+       _tmp0_ = self->priv->_p1;
+       result = _tmp0_;
+       return result;
+}
+
+void
+manam_foo_bar_baz_set_p1 (ManamFooBarBaz* self,
+                          const gchar* value)
+{
+       gchar* _tmp0_;
+       g_return_if_fail (MANAM_FOO_BAR_IS_BAZ (self));
+       _tmp0_ = g_strdup (value);
+       _g_free0 (self->priv->_p1);
+       self->priv->_p1 = _tmp0_;
+}
+
+static void
+manam_foo_bar_value_baz_init (GValue* value)
+{
+       value->data[0].v_pointer = NULL;
+}
+
+static void
+manam_foo_bar_value_baz_free_value (GValue* value)
+{
+       if (value->data[0].v_pointer) {
+               manam_foo_bar_baz_unref (value->data[0].v_pointer);
+       }
+}
+
+static void
+manam_foo_bar_value_baz_copy_value (const GValue* src_value,
+                                    GValue* dest_value)
+{
+       if (src_value->data[0].v_pointer) {
+               dest_value->data[0].v_pointer = manam_foo_bar_baz_ref (src_value->data[0].v_pointer);
+       } else {
+               dest_value->data[0].v_pointer = NULL;
+       }
+}
+
+static gpointer
+manam_foo_bar_value_baz_peek_pointer (const GValue* value)
+{
+       return value->data[0].v_pointer;
+}
+
+static gchar*
+manam_foo_bar_value_baz_collect_value (GValue* value,
+                                       guint n_collect_values,
+                                       GTypeCValue* collect_values,
+                                       guint collect_flags)
+{
+       if (collect_values[0].v_pointer) {
+               ManamFooBarBaz * object;
+               object = collect_values[0].v_pointer;
+               if (object->parent_instance.g_class == NULL) {
+                       return g_strconcat ("invalid unclassed object pointer for value type `", 
G_VALUE_TYPE_NAME (value), "'", NULL);
+               } else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) {
+                       return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE 
(object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL);
+               }
+               value->data[0].v_pointer = manam_foo_bar_baz_ref (object);
+       } else {
+               value->data[0].v_pointer = NULL;
+       }
+       return NULL;
+}
+
+static gchar*
+manam_foo_bar_value_baz_lcopy_value (const GValue* value,
+                                     guint n_collect_values,
+                                     GTypeCValue* collect_values,
+                                     guint collect_flags)
+{
+       ManamFooBarBaz ** object_p;
+       object_p = collect_values[0].v_pointer;
+       if (!object_p) {
+               return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
+       }
+       if (!value->data[0].v_pointer) {
+               *object_p = NULL;
+       } else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) {
+               *object_p = value->data[0].v_pointer;
+       } else {
+               *object_p = manam_foo_bar_baz_ref (value->data[0].v_pointer);
+       }
+       return NULL;
+}
+
+GParamSpec*
+manam_foo_bar_param_spec_baz (const gchar* name,
+                              const gchar* nick,
+                              const gchar* blurb,
+                              GType object_type,
+                              GParamFlags flags)
+{
+       ManamFooBarParamSpecBaz* spec;
+       g_return_val_if_fail (g_type_is_a (object_type, MANAM_FOO_BAR_TYPE_BAZ), NULL);
+       spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags);
+       G_PARAM_SPEC (spec)->value_type = object_type;
+       return G_PARAM_SPEC (spec);
+}
+
+gpointer
+manam_foo_bar_value_get_baz (const GValue* value)
+{
+       g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, MANAM_FOO_BAR_TYPE_BAZ), NULL);
+       return value->data[0].v_pointer;
+}
+
+void
+manam_foo_bar_value_set_baz (GValue* value,
+                             gpointer v_object)
+{
+       ManamFooBarBaz * old;
+       g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, MANAM_FOO_BAR_TYPE_BAZ));
+       old = value->data[0].v_pointer;
+       if (v_object) {
+               g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, MANAM_FOO_BAR_TYPE_BAZ));
+               g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE 
(value)));
+               value->data[0].v_pointer = v_object;
+               manam_foo_bar_baz_ref (value->data[0].v_pointer);
+       } else {
+               value->data[0].v_pointer = NULL;
+       }
+       if (old) {
+               manam_foo_bar_baz_unref (old);
+       }
+}
+
+void
+manam_foo_bar_value_take_baz (GValue* value,
+                              gpointer v_object)
+{
+       ManamFooBarBaz * old;
+       g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, MANAM_FOO_BAR_TYPE_BAZ));
+       old = value->data[0].v_pointer;
+       if (v_object) {
+               g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, MANAM_FOO_BAR_TYPE_BAZ));
+               g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE 
(value)));
+               value->data[0].v_pointer = v_object;
+       } else {
+               value->data[0].v_pointer = NULL;
+       }
+       if (old) {
+               manam_foo_bar_baz_unref (old);
+       }
+}
+
+static void
+manam_foo_bar_baz_class_init (ManamFooBarBazClass * klass,
+                              gpointer klass_data)
+{
+       manam_foo_bar_baz_parent_class = g_type_class_peek_parent (klass);
+       ((ManamFooBarBazClass *) klass)->finalize = manam_foo_bar_baz_finalize;
+       g_type_class_adjust_private_offset (klass, &ManamFooBarBaz_private_offset);
+       ((ManamFooBarBazClass *) klass)->v0 = (void (*) (ManamFooBarBaz*)) manam_foo_bar_baz_real_v0;
+       ((ManamFooBarBazClass *) klass)->v1 = (void (*) (ManamFooBarBaz*)) manam_foo_bar_baz_real_v1;
+}
+
+static void
+manam_foo_bar_baz_instance_init (ManamFooBarBaz * self,
+                                 gpointer klass)
+{
+       self->priv = manam_foo_bar_baz_get_instance_private (self);
+       self->ref_count = 1;
+}
+
+static void
+manam_foo_bar_baz_finalize (ManamFooBarBaz * obj)
+{
+       ManamFooBarBaz * self;
+       self = G_TYPE_CHECK_INSTANCE_CAST (obj, MANAM_FOO_BAR_TYPE_BAZ, ManamFooBarBaz);
+       g_signal_handlers_destroy (self);
+       _g_free0 (self->priv->_p0);
+       _g_free0 (self->f0);
+       _g_free0 (self->priv->_p1);
+       _g_free0 (self->f1);
+}
+
+static GType
+manam_foo_bar_baz_get_type_once (void)
+{
+       static const GTypeValueTable g_define_type_value_table = { manam_foo_bar_value_baz_init, 
manam_foo_bar_value_baz_free_value, manam_foo_bar_value_baz_copy_value, manam_foo_bar_value_baz_peek_pointer, 
"p", manam_foo_bar_value_baz_collect_value, "p", manam_foo_bar_value_baz_lcopy_value };
+       static const GTypeInfo g_define_type_info = { sizeof (ManamFooBarBazClass), (GBaseInitFunc) NULL, 
(GBaseFinalizeFunc) NULL, (GClassInitFunc) manam_foo_bar_baz_class_init, (GClassFinalizeFunc) NULL, NULL, 
sizeof (ManamFooBarBaz), 0, (GInstanceInitFunc) manam_foo_bar_baz_instance_init, &g_define_type_value_table };
+       static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | 
G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) };
+       GType manam_foo_bar_baz_type_id;
+       manam_foo_bar_baz_type_id = g_type_register_fundamental (g_type_fundamental_next (), 
"ManamFooBarBaz", &g_define_type_info, &g_define_type_fundamental_info, 0);
+       ManamFooBarBaz_private_offset = g_type_add_instance_private (manam_foo_bar_baz_type_id, sizeof 
(ManamFooBarBazPrivate));
+       return manam_foo_bar_baz_type_id;
+}
+
+GType
+manam_foo_bar_baz_get_type (void)
+{
+       static volatile gsize manam_foo_bar_baz_type_id__volatile = 0;
+       if (g_once_init_enter (&manam_foo_bar_baz_type_id__volatile)) {
+               GType manam_foo_bar_baz_type_id;
+               manam_foo_bar_baz_type_id = manam_foo_bar_baz_get_type_once ();
+               g_once_init_leave (&manam_foo_bar_baz_type_id__volatile, manam_foo_bar_baz_type_id);
+       }
+       return manam_foo_bar_baz_type_id__volatile;
+}
+
+gpointer
+manam_foo_bar_baz_ref (gpointer instance)
+{
+       ManamFooBarBaz * self;
+       self = instance;
+       g_atomic_int_inc (&self->ref_count);
+       return instance;
+}
+
+void
+manam_foo_bar_baz_unref (gpointer instance)
+{
+       ManamFooBarBaz * self;
+       self = instance;
+       if (g_atomic_int_dec_and_test (&self->ref_count)) {
+               MANAM_FOO_BAR_BAZ_GET_CLASS (self)->finalize (self);
+               g_type_free_instance ((GTypeInstance *) self);
+       }
+}
+
diff --git a/tests/objects/class-partial-nested.vala b/tests/objects/class-partial-nested.vala
new file mode 100644
index 000000000..03298ea4f
--- /dev/null
+++ b/tests/objects/class-partial-nested.vala
@@ -0,0 +1,34 @@
+namespace Manam.Foo {
+       public partial class Bar.Baz {
+               public string p0 { get; set; }
+               public string f0;
+               public void m0 () {
+               }
+               public virtual void v0 () {
+               }
+       }
+}
+
+namespace Manam.Foo {
+       public partial class Bar.Baz {
+               public string p1 { get; set; }
+               public string f1;
+               public void m1 () {
+               }
+               public virtual void v1 () {
+               }
+       }
+}
+
+void main () {
+       var baz = new Manam.Foo.Bar.Baz ();
+       baz.p0 = "p0";
+       baz.f0 = "f0";
+       baz.m0 ();
+       baz.v0 ();
+
+       baz.p1 = "p1";
+       baz.f1 = "f1";
+       baz.m1 ();
+       baz.v1 ();
+}
diff --git a/tests/objects/class-partial.c-expected b/tests/objects/class-partial.c-expected
index 0cf36ee73..ccc2533d7 100644
--- a/tests/objects/class-partial.c-expected
+++ b/tests/objects/class-partial.c-expected
@@ -42,6 +42,8 @@ typedef struct _IBarIface IBarIface;
 typedef struct _Foo Foo;
 typedef struct _FooClass FooClass;
 typedef struct _FooPrivate FooPrivate;
+#define _g_free0(var) (var = (g_free (var), NULL))
+#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
 enum  {
        FOO_0_PROPERTY,
        FOO_P0_PROPERTY,
@@ -50,7 +52,6 @@ enum  {
        FOO_NUM_PROPERTIES
 };
 static GParamSpec* foo_properties[FOO_NUM_PROPERTIES];
-#define _g_free0(var) (var = (g_free (var), NULL))
 enum  {
        FOO_S0_SIGNAL,
        FOO_S1_SIGNAL,
@@ -58,7 +59,6 @@ enum  {
        FOO_NUM_SIGNALS
 };
 static guint foo_signals[FOO_NUM_SIGNALS] = {0};
-#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
 #define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, 
__LINE__, G_STRFUNC, msg);
 #define _vala_return_if_fail(expr, msg) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, 
G_STRFUNC, msg); return; }
 #define _vala_return_val_if_fail(expr, msg, val) if G_LIKELY (expr) ; else { g_return_if_fail_warning 
(G_LOG_DOMAIN, G_STRFUNC, msg); return val; }
@@ -109,30 +109,31 @@ static GType ifoo_get_type_once (void);
 VALA_EXTERN GType ibar_get_type (void) G_GNUC_CONST ;
 VALA_EXTERN void ibar_i2 (IBar* self);
 static GType ibar_get_type_once (void);
+static void _vala_main (void);
 VALA_EXTERN GType foo_get_type (void) G_GNUC_CONST ;
 G_DEFINE_AUTOPTR_CLEANUP_FUNC (Foo, g_object_unref)
+VALA_EXTERN Foo* foo_new (void);
+VALA_EXTERN Foo* foo_construct (GType object_type);
+VALA_EXTERN void foo_set_p0 (Foo* self,
+                 const gchar* value);
+VALA_EXTERN void foo_m0 (Foo* self);
 VALA_EXTERN void foo_v0 (Foo* self);
+VALA_EXTERN void foo_set_p1 (Foo* self,
+                 const gchar* value);
+VALA_EXTERN void foo_m1 (Foo* self);
 VALA_EXTERN void foo_v1 (Foo* self);
+VALA_EXTERN void foo_set_p2 (Foo* self,
+                 const gchar* value);
+VALA_EXTERN void foo_m2 (Foo* self);
 VALA_EXTERN void foo_v2 (Foo* self);
-VALA_EXTERN void foo_m0 (Foo* self);
 static void foo_real_v0 (Foo* self);
-VALA_EXTERN Foo* foo_new (void);
-VALA_EXTERN Foo* foo_construct (GType object_type);
-VALA_EXTERN void foo_m1 (Foo* self);
 static void foo_real_v1 (Foo* self);
 static void foo_real_i1 (IFoo* base);
-VALA_EXTERN void foo_m2 (Foo* self);
 static void foo_real_v2 (Foo* self);
 static void foo_real_i2 (IBar* base);
 VALA_EXTERN const gchar* foo_get_p0 (Foo* self);
-VALA_EXTERN void foo_set_p0 (Foo* self,
-                 const gchar* value);
 VALA_EXTERN const gchar* foo_get_p1 (Foo* self);
-VALA_EXTERN void foo_set_p1 (Foo* self,
-                 const gchar* value);
 VALA_EXTERN const gchar* foo_get_p2 (Foo* self);
-VALA_EXTERN void foo_set_p2 (Foo* self,
-                 const gchar* value);
 static void foo_real_s0 (Foo* self);
 static void foo_real_s1 (Foo* self);
 static void foo_real_s2 (Foo* self);
@@ -146,7 +147,6 @@ static void _vala_foo_set_property (GObject * object,
                              guint property_id,
                              const GValue * value,
                              GParamSpec * pspec);
-static void _vala_main (void);
 
 void
 ifoo_i1 (IFoo* self)
@@ -224,6 +224,52 @@ ibar_get_type (void)
        return ibar_type_id__volatile;
 }
 
+static void
+_vala_main (void)
+{
+       Foo* foo = NULL;
+       Foo* _tmp0_;
+       gchar* _tmp1_;
+       gchar* _tmp2_;
+       gchar* _tmp3_;
+       _tmp0_ = foo_new ();
+       foo = _tmp0_;
+       foo_set_p0 (foo, "p0");
+       _tmp1_ = g_strdup ("f0");
+       _g_free0 (foo->f0);
+       foo->f0 = _tmp1_;
+       foo_m0 (foo);
+       foo_v0 (foo);
+       g_signal_emit (foo, foo_signals[FOO_S0_SIGNAL], 0);
+       foo_set_p1 (foo, "p1");
+       _tmp2_ = g_strdup ("f1");
+       _g_free0 (foo->f1);
+       foo->f1 = _tmp2_;
+       foo_m1 (foo);
+       foo_v1 (foo);
+       g_signal_emit (foo, foo_signals[FOO_S1_SIGNAL], 0);
+       foo_set_p2 (foo, "p2");
+       _tmp3_ = g_strdup ("f2");
+       _g_free0 (foo->f2);
+       foo->f2 = _tmp3_;
+       foo_m2 (foo);
+       foo_v2 (foo);
+       g_signal_emit (foo, foo_signals[FOO_S2_SIGNAL], 0);
+       _vala_assert (IS_IFOO (foo), "foo is IFoo");
+       ifoo_i1 (G_TYPE_CHECK_INSTANCE_CAST (foo, TYPE_IFOO, IFoo));
+       _vala_assert (IS_IBAR (foo), "foo is IBar");
+       ibar_i2 (G_TYPE_CHECK_INSTANCE_CAST (foo, TYPE_IBAR, IBar));
+       _g_object_unref0 (foo);
+}
+
+int
+main (int argc,
+      char ** argv)
+{
+       _vala_main ();
+       return 0;
+}
+
 static inline gpointer
 foo_get_instance_private (Foo* self)
 {
@@ -554,49 +600,3 @@ _vala_foo_set_property (GObject * object,
        }
 }
 
-static void
-_vala_main (void)
-{
-       Foo* foo = NULL;
-       Foo* _tmp0_;
-       gchar* _tmp1_;
-       gchar* _tmp2_;
-       gchar* _tmp3_;
-       _tmp0_ = foo_new ();
-       foo = _tmp0_;
-       foo_set_p0 (foo, "p0");
-       _tmp1_ = g_strdup ("f0");
-       _g_free0 (foo->f0);
-       foo->f0 = _tmp1_;
-       foo_m0 (foo);
-       foo_v0 (foo);
-       g_signal_emit (foo, foo_signals[FOO_S0_SIGNAL], 0);
-       foo_set_p1 (foo, "p1");
-       _tmp2_ = g_strdup ("f1");
-       _g_free0 (foo->f1);
-       foo->f1 = _tmp2_;
-       foo_m1 (foo);
-       foo_v1 (foo);
-       g_signal_emit (foo, foo_signals[FOO_S1_SIGNAL], 0);
-       foo_set_p2 (foo, "p2");
-       _tmp3_ = g_strdup ("f2");
-       _g_free0 (foo->f2);
-       foo->f2 = _tmp3_;
-       foo_m2 (foo);
-       foo_v2 (foo);
-       g_signal_emit (foo, foo_signals[FOO_S2_SIGNAL], 0);
-       _vala_assert (IS_IFOO (foo), "foo is IFoo");
-       ifoo_i1 (G_TYPE_CHECK_INSTANCE_CAST (foo, TYPE_IFOO, IFoo));
-       _vala_assert (IS_IBAR (foo), "foo is IBar");
-       ibar_i2 (G_TYPE_CHECK_INSTANCE_CAST (foo, TYPE_IBAR, IBar));
-       _g_object_unref0 (foo);
-}
-
-int
-main (int argc,
-      char ** argv)
-{
-       _vala_main ();
-       return 0;
-}
-
diff --git a/vala/valaparser.vala b/vala/valaparser.vala
index d61a581e0..112a0d04d 100644
--- a/vala/valaparser.vala
+++ b/vala/valaparser.vala
@@ -44,12 +44,20 @@ public class Vala.Parser : CodeVisitor {
        static List<TypeParameter> _empty_type_parameter_list;
        static int next_local_func_id = 0;
 
+       PartialInfo[] partials;
+
        struct TokenInfo {
                public TokenType type;
                public SourceLocation begin;
                public SourceLocation end;
        }
 
+       struct PartialInfo {
+               public Symbol parent;
+               public SourceLocation begin;
+               public List<Attribute>? attributes;
+       }
+
        [Flags]
        enum ModifierFlags {
                NONE = 0,
@@ -211,6 +219,20 @@ public class Vala.Parser : CodeVisitor {
                }
        }
 
+       void jump (SourceLocation location) {
+               while (tokens[index].begin.pos != location.pos) {
+                       index = (index + 1) % BUFFER_SIZE;
+                       size--;
+                       if (size <= 0) {
+                               scanner.seek (location);
+                               size = 0;
+                               index = 0;
+
+                               next ();
+                       }
+               }
+       }
+
        void skip_identifier () throws ParseError {
                // also accept keywords as identifiers where there is no conflict
                switch (current ()) {
@@ -386,6 +408,8 @@ public class Vala.Parser : CodeVisitor {
 
 
                try {
+                       partials = new PartialInfo[] {};
+                       var begin = get_location ();
                        parse_using_directives (context.root);
                        parse_declarations (context.root, true);
                        if (accept (TokenType.CLOSE_BRACE)) {
@@ -394,6 +418,14 @@ public class Vala.Parser : CodeVisitor {
                                        Report.error (get_last_src (), "unexpected `}'");
                                }
                        }
+                       if (partials.length > 0) {
+                               rollback (begin);
+                               foreach (var info in partials) {
+                                       jump (info.begin);
+                                       parse_class_declaration (info.parent, info.attributes, true);
+                               }
+                       }
+                       partials = null;
                } catch (ParseError e) {
                        report_parse_error (e);
                }
@@ -2903,7 +2935,7 @@ public class Vala.Parser : CodeVisitor {
                }
        }
 
-       void parse_class_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
+       void parse_class_declaration (Symbol parent, List<Attribute>? attrs, bool partial_reparse = false) 
throws ParseError {
                var begin = get_location ();
                var access = parse_access_modifier ();
                var flags = parse_type_declaration_modifiers ();
@@ -2935,7 +2967,30 @@ public class Vala.Parser : CodeVisitor {
                        cl.is_extern = true;
                }
 
-               var old_cl = parent.scope.lookup (cl.name) as Class;
+               Class? old_cl = null;
+               if (partial_reparse) {
+                       var names = new ArrayList<string> ();
+                       while (sym.inner != null) {
+                               sym = sym.inner;
+                               names.insert (0, sym.name);
+                       }
+                       Symbol p = parent;
+                       while (p != null && p != context.root) {
+                               names.insert (0, p.name);
+                               p = p.parent_symbol;
+                       }
+                       p = context.root;
+                       foreach (var name in names) {
+                               p = p.scope.lookup (name);
+                               if (p == null) {
+                                       break;
+                               }
+                       }
+                       if (p != null) {
+                               old_cl = p.scope.lookup (cl.name) as Class;
+                               parent = p;
+                       }
+               }
                if (old_cl != null && old_cl.is_partial) {
                        if (cl.is_partial != old_cl.is_partial) {
                                Report.error (cl.source_reference, "conflicting partial and not partial 
declarations of `%s'".printf (cl.name));
@@ -2984,6 +3039,11 @@ public class Vala.Parser : CodeVisitor {
                        cl.add_method (m);
                }
 
+               if (partial_reparse) {
+                       parent.add_class (cl);
+                       return;
+               }
+
                Symbol result = cl;
                while (sym != null) {
                        sym = sym.inner;
@@ -2991,7 +3051,10 @@ public class Vala.Parser : CodeVisitor {
                        Symbol next = (sym != null ? new Namespace (sym.name, cl.source_reference) : parent);
                        if (result is Namespace) {
                                next.add_namespace ((Namespace) result);
-                       } else {
+                       } else if (!partial_reparse && cl.is_partial) {
+                               PartialInfo info = { parent, begin, attrs };
+                               partials += info;
+                       } else if (!cl.is_partial) {
                                next.add_class ((Class) result);
                        }
                        result = next;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]