summaryrefslogtreecommitdiff
path: root/vala
diff options
context:
space:
mode:
authorJürg Billeter <j@bitron.ch>2007-05-02 09:42:00 +0000
committerJürg Billeter <juergbi@src.gnome.org>2007-05-02 09:42:00 +0000
commitf8387ad143f1884f8f5f89bd5389605624f4c34f (patch)
treee75e563fc9535200ec146af72962e80778359ae4 /vala
parent9db973114ee1449c1764404163ecc8294f8e73d2 (diff)
downloadvala-f8387ad143f1884f8f5f89bd5389605624f4c34f.tar.gz
Move contents of vala-pkg to trunk
2007-05-02 Jürg Billeter <j@bitron.ch> * Move contents of vala-pkg to trunk svn path=/trunk/; revision=300
Diffstat (limited to 'vala')
-rw-r--r--vala/Makefile.am450
-rw-r--r--vala/parser.y3513
-rw-r--r--vala/scanner.l193
-rw-r--r--vala/vala.h78
-rw-r--r--vala/valaaddressofexpression.vala64
-rw-r--r--vala/valaarray.vala201
-rw-r--r--vala/valaarraycreationexpression.vala89
-rw-r--r--vala/valaarraylengthfield.vala46
-rw-r--r--vala/valaarrayresizemethod.vala53
-rw-r--r--vala/valaassignment.vala113
-rw-r--r--vala/valaattribute.vala142
-rw-r--r--vala/valaattributeprocessor.vala86
-rw-r--r--vala/valabaseaccess.vala46
-rw-r--r--vala/valabinaryexpression.vala117
-rw-r--r--vala/valablock.vala92
-rw-r--r--vala/valabooleanliteral.vala57
-rw-r--r--vala/valabreakstatement.vala42
-rw-r--r--vala/valacallback.vala202
-rw-r--r--vala/valacastexpression.vala74
-rw-r--r--vala/valacatchclause.vala69
-rw-r--r--vala/valacharacterliteral.vala80
-rw-r--r--vala/valaclass.vala398
-rw-r--r--vala/valaclassregisterfunction.vala105
-rw-r--r--vala/valacodecontext.vala237
-rw-r--r--vala/valacodegenerator.vala4177
-rw-r--r--vala/valacodenode.vala118
-rw-r--r--vala/valacodevisitor.vala838
-rw-r--r--vala/valaconditionalexpression.vala66
-rw-r--r--vala/valaconstant.vala114
-rw-r--r--vala/valaconstructor.vala67
-rw-r--r--vala/valacontinuestatement.vala42
-rw-r--r--vala/valacreationmethod.vala67
-rw-r--r--vala/valadatatype.vala310
-rw-r--r--vala/valadeclarationstatement.vala51
-rw-r--r--vala/valadestructor.vala67
-rw-r--r--vala/valadostatement.vala78
-rw-r--r--vala/valaelementaccess.vala60
-rw-r--r--vala/valaemptystatement.vala42
-rw-r--r--vala/valaenum.vala152
-rw-r--r--vala/valaenumvalue.vala79
-rw-r--r--vala/valaexpression.vala76
-rw-r--r--vala/valaexpressionstatement.vala85
-rw-r--r--vala/valafield.vala173
-rw-r--r--vala/valaflags.vala150
-rw-r--r--vala/valaflagsvalue.vala80
-rw-r--r--vala/valaforeachstatement.vala97
-rw-r--r--vala/valaformalparameter.vala120
-rw-r--r--vala/valaforstatement.vala150
-rw-r--r--vala/valaifstatement.vala87
-rw-r--r--vala/valainitializerlist.vala68
-rw-r--r--vala/valainstancecast.vala58
-rw-r--r--vala/valaintegerliteral.vala103
-rw-r--r--vala/valainterface.vala309
-rw-r--r--vala/valainterfaceregisterfunction.vala83
-rw-r--r--vala/valainterfacewriter.vala619
-rw-r--r--vala/valainvocationexpression.vala106
-rw-r--r--vala/valainvokable.vala49
-rw-r--r--vala/valalambdaexpression.vala109
-rw-r--r--vala/valaliteral.vala33
-rw-r--r--vala/valaliteralexpression.vala55
-rw-r--r--vala/valalocalvariabledeclaration.vala90
-rw-r--r--vala/valalockable.vala36
-rw-r--r--vala/valalockstatement.vala50
-rw-r--r--vala/valamember.vala30
-rw-r--r--vala/valamemberaccess.vala114
-rw-r--r--vala/valamemberaccessibility.vala30
-rw-r--r--vala/valamemorymanager.vala252
-rw-r--r--vala/valamethod.vala322
-rw-r--r--vala/valanamedargument.vala59
-rw-r--r--vala/valanamespace.vala379
-rw-r--r--vala/valanamespacereference.vala54
-rw-r--r--vala/valanullliteral.vala46
-rw-r--r--vala/valaobjectcreationexpression.vala110
-rw-r--r--vala/valaparenthesizedexpression.vala67
-rw-r--r--vala/valaparser.vala94
-rw-r--r--vala/valapointer.vala90
-rw-r--r--vala/valapointerindirection.vala64
-rw-r--r--vala/valapostfixexpression.vala58
-rw-r--r--vala/valaproperty.vala231
-rw-r--r--vala/valapropertyaccessor.vala82
-rw-r--r--vala/valarealliteral.vala62
-rw-r--r--vala/valareferencetransferexpression.vala64
-rw-r--r--vala/valareport.vala75
-rw-r--r--vala/valareturnstatement.vala75
-rw-r--r--vala/valasemanticanalyzer.vala2341
-rw-r--r--vala/valasignal.vala189
-rw-r--r--vala/valasourcefile.vala355
-rw-r--r--vala/valasourcefilecycle.vala38
-rw-r--r--vala/valasourcereference.vala103
-rw-r--r--vala/valastatement.vala39
-rw-r--r--vala/valastringliteral.vala65
-rw-r--r--vala/valastruct.vala436
-rw-r--r--vala/valaswitchlabel.vala65
-rw-r--r--vala/valaswitchsection.vala99
-rw-r--r--vala/valaswitchstatement.vala92
-rw-r--r--vala/valasymbol.vala119
-rw-r--r--vala/valasymbolbuilder.vala429
-rw-r--r--vala/valasymbolresolver.vala249
-rw-r--r--vala/valathrowstatement.vala73
-rw-r--r--vala/valatrystatement.vala66
-rw-r--r--vala/valatypecheck.vala60
-rw-r--r--vala/valatypeofexpression.vala51
-rw-r--r--vala/valatypeparameter.vala104
-rw-r--r--vala/valatypereference.vala389
-rw-r--r--vala/valatyperegisterfunction.vala186
-rw-r--r--vala/valaunaryexpression.vala87
-rw-r--r--vala/valavariabledeclarator.vala111
-rw-r--r--vala/valawhilestatement.vala78
108 files changed, 23843 insertions, 0 deletions
diff --git a/vala/Makefile.am b/vala/Makefile.am
new file mode 100644
index 000000000..f9a1fb15c
--- /dev/null
+++ b/vala/Makefile.am
@@ -0,0 +1,450 @@
+NULL =
+
+INCLUDES = \
+ $(GLIB_CFLAGS) \
+ $(NULL)
+
+BUILT_SOURCES = parser.h vala.vala.stamp
+AM_YFLAGS = -d
+
+lib_LTLIBRARIES = \
+ libvala.la
+ $(NULL)
+
+libvala_la_SOURCES = \
+ parser.y \
+ scanner.l \
+ vala.h \
+ vala.vala.stamp \
+ valaaddressofexpression.c \
+ valaaddressofexpression.h \
+ valaaddressofexpression.vala \
+ valaarray.c \
+ valaarray.h \
+ valaarray.vala \
+ valaarraycreationexpression.c \
+ valaarraycreationexpression.h \
+ valaarraycreationexpression.vala \
+ valaarraylengthfield.c \
+ valaarraylengthfield.h \
+ valaarraylengthfield.vala \
+ valaarrayresizemethod.c \
+ valaarrayresizemethod.h \
+ valaarrayresizemethod.vala \
+ valaassignment.c \
+ valaassignment.h \
+ valaassignment.vala \
+ valaattribute.c \
+ valaattribute.h \
+ valaattribute.vala \
+ valaattributeprocessor.c \
+ valaattributeprocessor.h \
+ valaattributeprocessor.vala \
+ valabaseaccess.c \
+ valabaseaccess.h \
+ valabaseaccess.vala \
+ valabinaryexpression.c \
+ valabinaryexpression.h \
+ valabinaryexpression.vala \
+ valablock.c \
+ valablock.h \
+ valablock.vala \
+ valabooleanliteral.c \
+ valabooleanliteral.h \
+ valabooleanliteral.vala \
+ valabreakstatement.c \
+ valabreakstatement.h \
+ valabreakstatement.vala \
+ valacallback.c \
+ valacallback.h \
+ valacallback.vala \
+ valacastexpression.c \
+ valacastexpression.h \
+ valacastexpression.vala \
+ valacatchclause.c \
+ valacatchclause.h \
+ valacatchclause.vala \
+ valacharacterliteral.c \
+ valacharacterliteral.h \
+ valacharacterliteral.vala \
+ valaclass.c \
+ valaclass.h \
+ valaclass.vala \
+ valaclassregisterfunction.c \
+ valaclassregisterfunction.h \
+ valaclassregisterfunction.vala \
+ valacodecontext.c \
+ valacodecontext.h \
+ valacodecontext.vala \
+ valacodegenerator.c \
+ valacodegenerator.h \
+ valacodegenerator.vala \
+ valacodenode.c \
+ valacodenode.h \
+ valacodenode.vala \
+ valacodevisitor.c \
+ valacodevisitor.h \
+ valacodevisitor.vala \
+ valaconditionalexpression.c \
+ valaconditionalexpression.h \
+ valaconditionalexpression.vala \
+ valaconstant.c \
+ valaconstant.h \
+ valaconstant.vala \
+ valaconstructor.c \
+ valaconstructor.h \
+ valaconstructor.vala \
+ valacontinuestatement.c \
+ valacontinuestatement.h \
+ valacontinuestatement.vala \
+ valacreationmethod.c \
+ valacreationmethod.h \
+ valacreationmethod.vala \
+ valadatatype.c \
+ valadatatype.h \
+ valadatatype.vala \
+ valadeclarationstatement.c \
+ valadeclarationstatement.h \
+ valadeclarationstatement.vala \
+ valadestructor.c \
+ valadestructor.h \
+ valadestructor.vala \
+ valadostatement.c \
+ valadostatement.h \
+ valadostatement.vala \
+ valaelementaccess.c \
+ valaelementaccess.h \
+ valaelementaccess.vala \
+ valaemptystatement.c \
+ valaemptystatement.h \
+ valaemptystatement.vala \
+ valaenum.c \
+ valaenum.h \
+ valaenum.vala \
+ valaenumvalue.c \
+ valaenumvalue.h \
+ valaenumvalue.vala \
+ valaexpression.c \
+ valaexpression.h \
+ valaexpression.vala \
+ valaexpressionstatement.c \
+ valaexpressionstatement.h \
+ valaexpressionstatement.vala \
+ valafield.c \
+ valafield.h \
+ valafield.vala \
+ valaflags.c \
+ valaflags.h \
+ valaflags.vala \
+ valaflagsvalue.c \
+ valaflagsvalue.h \
+ valaflagsvalue.vala \
+ valaforeachstatement.c \
+ valaforeachstatement.h \
+ valaforeachstatement.vala \
+ valaformalparameter.c \
+ valaformalparameter.h \
+ valaformalparameter.vala \
+ valaforstatement.c \
+ valaforstatement.h \
+ valaforstatement.vala \
+ valaifstatement.c \
+ valaifstatement.h \
+ valaifstatement.vala \
+ valainitializerlist.c \
+ valainitializerlist.h \
+ valainitializerlist.vala \
+ valainstancecast.c \
+ valainstancecast.h \
+ valainstancecast.vala \
+ valaintegerliteral.c \
+ valaintegerliteral.h \
+ valaintegerliteral.vala \
+ valainterface.c \
+ valainterface.h \
+ valainterface.vala \
+ valainterfaceregisterfunction.c \
+ valainterfaceregisterfunction.h \
+ valainterfaceregisterfunction.vala \
+ valainterfacewriter.c \
+ valainterfacewriter.h \
+ valainterfacewriter.vala \
+ valainvocationexpression.c \
+ valainvocationexpression.h \
+ valainvocationexpression.vala \
+ valainvokable.c \
+ valainvokable.h \
+ valainvokable.vala \
+ valalambdaexpression.c \
+ valalambdaexpression.h \
+ valalambdaexpression.vala \
+ valaliteral.c \
+ valaliteral.h \
+ valaliteral.vala \
+ valaliteralexpression.c \
+ valaliteralexpression.h \
+ valaliteralexpression.vala \
+ valalocalvariabledeclaration.c \
+ valalocalvariabledeclaration.h \
+ valalocalvariabledeclaration.vala \
+ valalockable.c \
+ valalockable.h \
+ valalockable.vala \
+ valalockstatement.c \
+ valalockstatement.h \
+ valalockstatement.vala \
+ valamember.c \
+ valamember.h \
+ valamember.vala \
+ valamemberaccess.c \
+ valamemberaccess.h \
+ valamemberaccess.vala \
+ valamemberaccessibility.c \
+ valamemberaccessibility.h \
+ valamemberaccessibility.vala \
+ valamemorymanager.c \
+ valamemorymanager.h \
+ valamemorymanager.vala \
+ valamethod.c \
+ valamethod.h \
+ valamethod.vala \
+ valanamedargument.c \
+ valanamedargument.h \
+ valanamedargument.vala \
+ valanamespace.c \
+ valanamespace.h \
+ valanamespace.vala \
+ valanamespacereference.c \
+ valanamespacereference.h \
+ valanamespacereference.vala \
+ valanullliteral.c \
+ valanullliteral.h \
+ valanullliteral.vala \
+ valaobjectcreationexpression.c \
+ valaobjectcreationexpression.h \
+ valaobjectcreationexpression.vala \
+ valaparenthesizedexpression.c \
+ valaparenthesizedexpression.h \
+ valaparenthesizedexpression.vala \
+ valaparser.c \
+ valaparser.h \
+ valaparser.vala \
+ valapointer.c \
+ valapointer.h \
+ valapointer.vala \
+ valapointerindirection.c \
+ valapointerindirection.h \
+ valapointerindirection.vala \
+ valapostfixexpression.c \
+ valapostfixexpression.h \
+ valapostfixexpression.vala \
+ valapropertyaccessor.c \
+ valapropertyaccessor.h \
+ valapropertyaccessor.vala \
+ valaproperty.c \
+ valaproperty.h \
+ valaproperty.vala \
+ valarealliteral.c \
+ valarealliteral.h \
+ valarealliteral.vala \
+ valareferencetransferexpression.c \
+ valareferencetransferexpression.h \
+ valareferencetransferexpression.vala \
+ valareport.c \
+ valareport.h \
+ valareport.vala \
+ valareturnstatement.c \
+ valareturnstatement.h \
+ valareturnstatement.vala \
+ valasemanticanalyzer.c \
+ valasemanticanalyzer.h \
+ valasemanticanalyzer.vala \
+ valasignal.c \
+ valasignal.h \
+ valasignal.vala \
+ valasourcefile.c \
+ valasourcefile.h \
+ valasourcefile.vala \
+ valasourcefilecycle.c \
+ valasourcefilecycle.h \
+ valasourcefilecycle.vala \
+ valasourcereference.c \
+ valasourcereference.h \
+ valasourcereference.vala \
+ valastatement.c \
+ valastatement.h \
+ valastatement.vala \
+ valastringliteral.c \
+ valastringliteral.h \
+ valastringliteral.vala \
+ valastruct.c \
+ valastruct.h \
+ valastruct.vala \
+ valaswitchlabel.c \
+ valaswitchlabel.h \
+ valaswitchlabel.vala \
+ valaswitchsection.c \
+ valaswitchsection.h \
+ valaswitchsection.vala \
+ valaswitchstatement.c \
+ valaswitchstatement.h \
+ valaswitchstatement.vala \
+ valasymbolbuilder.c \
+ valasymbolbuilder.h \
+ valasymbolbuilder.vala \
+ valasymbol.c \
+ valasymbol.h \
+ valasymbol.vala \
+ valasymbolresolver.c \
+ valasymbolresolver.h \
+ valasymbolresolver.vala \
+ valathrowstatement.c \
+ valathrowstatement.h \
+ valathrowstatement.vala \
+ valatrystatement.c \
+ valatrystatement.h \
+ valatrystatement.vala \
+ valatypecheck.c \
+ valatypecheck.h \
+ valatypecheck.vala \
+ valatypeofexpression.c \
+ valatypeofexpression.h \
+ valatypeofexpression.vala \
+ valatypeparameter.c \
+ valatypeparameter.h \
+ valatypeparameter.vala \
+ valatypereference.c \
+ valatypereference.h \
+ valatypereference.vala \
+ valatyperegisterfunction.c \
+ valatyperegisterfunction.h \
+ valatyperegisterfunction.vala \
+ valaunaryexpression.c \
+ valaunaryexpression.h \
+ valaunaryexpression.vala \
+ valavariabledeclarator.c \
+ valavariabledeclarator.h \
+ valavariabledeclarator.vala \
+ valawhilestatement.c \
+ valawhilestatement.h \
+ valawhilestatement.vala \
+ $(NULL)
+
+valaincludedir = $(includedir)/vala-1.0/vala
+
+valainclude_HEADERS = \
+ vala.h \
+ valaaddressofexpression.h \
+ valaarray.h \
+ valaarraycreationexpression.h \
+ valaassignment.h \
+ valaattribute.h \
+ valaattributeprocessor.h \
+ valabaseaccess.h \
+ valabinaryexpression.h \
+ valablock.h \
+ valabooleanliteral.h \
+ valabreakstatement.h \
+ valacallback.h \
+ valacastexpression.h \
+ valacatchclause.h \
+ valacharacterliteral.h \
+ valaclass.h \
+ valaclassregisterfunction.h \
+ valacodecontext.h \
+ valacodegenerator.h \
+ valacodenode.h \
+ valacodevisitor.h \
+ valaconditionalexpression.h \
+ valaconstant.h \
+ valaconstructor.h \
+ valacontinuestatement.h \
+ valacreationmethod.h \
+ valadatatype.h \
+ valadeclarationstatement.h \
+ valadestructor.h \
+ valadostatement.h \
+ valaelementaccess.h \
+ valaemptystatement.h \
+ valaenum.h \
+ valaenumvalue.h \
+ valaexpression.h \
+ valaexpressionstatement.h \
+ valafield.h \
+ valaflags.h \
+ valaflagsvalue.h \
+ valaforeachstatement.h \
+ valaformalparameter.h \
+ valaforstatement.h \
+ valaifstatement.h \
+ valainitializerlist.h \
+ valainstancecast.h \
+ valaintegerliteral.h \
+ valainterface.h \
+ valainterfaceregisterfunction.h \
+ valainterfacewriter.h \
+ valainvocationexpression.h \
+ valainvokable.h \
+ valalambdaexpression.h \
+ valaliteral.h \
+ valaliteralexpression.h \
+ valalocalvariabledeclaration.h \
+ valalockable.h \
+ valalockstatement.h \
+ valamember.h \
+ valamemberaccess.h \
+ valamemberaccessibility.h \
+ valamemorymanager.h \
+ valamethod.h \
+ valanamedargument.h \
+ valanamespace.h \
+ valanamespacereference.h \
+ valanullliteral.h \
+ valaobjectcreationexpression.h \
+ valaparenthesizedexpression.h \
+ valaparser.h \
+ valapointer.h \
+ valapointerindirection.h \
+ valapostfixexpression.h \
+ valapropertyaccessor.h \
+ valaproperty.h \
+ valarealliteral.h \
+ valareferencetransferexpression.h \
+ valareport.h \
+ valareturnstatement.h \
+ valasemanticanalyzer.h \
+ valasignal.h \
+ valasourcefile.h \
+ valasourcefilecycle.h \
+ valasourcereference.h \
+ valastatement.h \
+ valastringliteral.h \
+ valastruct.h \
+ valaswitchlabel.h \
+ valaswitchsection.h \
+ valaswitchstatement.h \
+ valasymbolbuilder.h \
+ valasymbol.h \
+ valasymbolresolver.h \
+ valathrowstatement.h \
+ valatrystatement.h \
+ valatypecheck.h \
+ valatypeofexpression.h \
+ valatypeparameter.h \
+ valatypereference.h \
+ valatyperegisterfunction.h \
+ valaunaryexpression.h \
+ valavariabledeclarator.h \
+ valawhilestatement.h \
+ $(NULL)
+
+vala.vala vala.vala.stamp: $(filter %.vala,$(libvala_la_SOURCES))
+ $(VALAC) --vapidir $(srcdir)/../vapi --vapidir ../ccode --pkg ccode --library vala $^
+ touch $@
+
+libvala_la_LIBADD = \
+ $(GLIB_LIBS) \
+ ../ccode/libvalaccode.la \
+ $(NULL)
+
+EXTRA_DIST = vala.vala vala.vala.stamp
diff --git a/vala/parser.y b/vala/parser.y
new file mode 100644
index 000000000..b42975439
--- /dev/null
+++ b/vala/parser.y
@@ -0,0 +1,3513 @@
+/* parser.y
+ *
+ * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
+ *
+ * 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>
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+%{
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "vala.h"
+#include "parser.h"
+
+#define src(l) (vala_source_reference_new (current_source_file, l.first_line, l.first_column, l.last_line, l.last_column))
+
+#define src_com(l,c) (vala_source_reference_new_with_comment (current_source_file, l.first_line, l.first_column, l.last_line, l.last_column, c))
+
+static ValaSourceFile *current_source_file;
+static ValaNamespace *current_namespace;
+static gboolean current_namespace_implicit;
+static ValaClass *current_class;
+static ValaStruct *current_struct;
+static ValaInterface *current_interface;
+
+typedef enum {
+ VALA_MODIFIER_NONE,
+ VALA_MODIFIER_ABSTRACT = 1 << 0,
+ VALA_MODIFIER_OVERRIDE = 1 << 1,
+ VALA_MODIFIER_STATIC = 1 << 2,
+ VALA_MODIFIER_VIRTUAL = 1 << 3,
+} ValaModifier;
+
+int yylex (YYSTYPE *yylval_param, YYLTYPE *yylloc_param, ValaParser *parser);
+static void yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg);
+%}
+
+%defines
+%locations
+%pure-parser
+%parse-param {ValaParser *parser}
+%lex-param {ValaParser *parser}
+%error-verbose
+%union {
+ int num;
+ char *str;
+ GList *list;
+ ValaLiteral *literal;
+ ValaTypeReference *type_reference;
+ ValaExpression *expression;
+ ValaStatement *statement;
+ ValaNamespace *namespace;
+ ValaClass *class;
+ ValaStruct *struct_;
+ ValaInterface *interface;
+ ValaEnum *enum_;
+ ValaEnumValue *enum_value;
+ ValaFlags *flags;
+ ValaFlagsValue *flags_value;
+ ValaCallback *callback;
+ ValaConstant *constant;
+ ValaField *field;
+ ValaMethod *method;
+ ValaFormalParameter *formal_parameter;
+ ValaProperty *property;
+ ValaPropertyAccessor *property_accessor;
+ ValaSignal *signal;
+ ValaConstructor *constructor;
+ ValaDestructor *destructor;
+ ValaLocalVariableDeclaration *local_variable_declaration;
+ ValaVariableDeclarator *variable_declarator;
+ ValaTypeParameter *type_parameter;
+ ValaAttribute *attribute;
+ ValaNamedArgument *named_argument;
+ ValaSwitchSection *switch_section;
+ ValaSwitchLabel *switch_label;
+ ValaCatchClause *catch_clause;
+}
+
+%token OPEN_BRACE "{"
+%token CLOSE_BRACE "}"
+%token OPEN_PARENS "("
+%token OPEN_CAST_PARENS "cast ("
+%token CLOSE_PARENS ")"
+%token BRACKET_PAIR "[]"
+%token OPEN_BRACKET "["
+%token CLOSE_BRACKET "]"
+%token ELLIPSIS "..."
+%token DOT "."
+%token COLON ":"
+%token COMMA ","
+%token SEMICOLON ";"
+%token HASH "#"
+%token INTERR "?"
+
+%token ASSIGN_BITWISE_OR "|="
+%token ASSIGN_BITWISE_AND "&="
+%token ASSIGN_BITWISE_XOR "^="
+%token ASSIGN_ADD "+="
+%token ASSIGN_SUB "-="
+%token ASSIGN_MUL "*="
+%token ASSIGN_DIV "/="
+%token ASSIGN_PERCENT "%="
+%token ASSIGN_SHIFT_LEFT "<<="
+%token ASSIGN_SHIFT_RIGHT ">>="
+
+%token OP_INC "++"
+%token OP_DEC "--"
+%token OP_EQ "=="
+%token OP_NE "!="
+%token OP_SHIFT_LEFT "<<"
+%token OP_SHIFT_RIGHT ">>"
+%token OP_LE "<="
+%token OP_GE ">="
+%token LAMBDA "=>"
+%token GENERIC_LT "generic <"
+%token OP_LT "<"
+%token OP_GT ">"
+%token OP_NEG "!"
+%token CARRET "^"
+%token BITWISE_OR "|"
+%token BITWISE_AND "&"
+%token OP_OR "||"
+%token OP_AND "&&"
+%token TILDE "~"
+
+%token ASSIGN "="
+%token PLUS "+"
+%token MINUS "-"
+%token STAR "*"
+%token DIV "/"
+%token PERCENT "%"
+
+%token ABSTRACT "abstract"
+%token BASE "base"
+%token BREAK "break"
+%token CALLBACK "callback"
+%token CASE "case"
+%token CATCH "catch"
+%token CLASS "class"
+%token CONST "const"
+%token CONSTRUCT "construct"
+%token CONTINUE "continue"
+%token DEFAULT "default"
+%token DO "do"
+%token ELSE "else"
+%token ENUM "enum"
+%token VALA_FALSE "false"
+%token FINALLY "finally"
+%token FLAGS "flags"
+%token FOR "for"
+%token FOREACH "foreach"
+%token GET "get"
+%token IF "if"
+%token IN "in"
+%token INTERFACE "interface"
+%token IS "is"
+%token LOCK "lock"
+%token NAMESPACE "namespace"
+%token NEW "new"
+%token VALA_NULL "null"
+%token OUT "out"
+%token OVERRIDE "override"
+%token PRIVATE "private"
+%token PROTECTED "protected"
+%token PUBLIC "public"
+%token REF "ref"
+%token RETURN "return"
+%token SET "set"
+%token SIGNAL "signal"
+%token STATIC "static"
+%token STRUCT "struct"
+%token SWITCH "switch"
+%token THIS "this"
+%token THROW "throw"
+%token THROWS "throws"
+%token VALA_TRUE "true"
+%token TRY "try"
+%token TYPEOF "typeof"
+%token USING "using"
+%token VAR "var"
+%token VIRTUAL "virtual"
+%token WEAK "weak"
+%token WHILE "while"
+
+%token <str> IDENTIFIER "identifier"
+%token <str> INTEGER_LITERAL "integer"
+%token <str> REAL_LITERAL "real"
+%token <str> CHARACTER_LITERAL "character"
+%token <str> STRING_LITERAL "string"
+
+%type <str> comment
+%type <str> identifier
+%type <literal> literal
+%type <literal> boolean_literal
+%type <num> stars
+%type <type_reference> type_name
+%type <type_reference> type
+%type <list> opt_argument_list
+%type <list> argument_list
+%type <expression> argument
+%type <expression> primary_expression
+%type <expression> array_creation_expression
+%type <list> size_specifier_list
+%type <expression> opt_initializer
+%type <num> opt_rank_specifier
+%type <num> rank_specifier
+%type <num> opt_bracket_pair
+%type <num> bracket_pair
+%type <num> opt_comma_list
+%type <num> comma_list
+%type <expression> primary_no_array_creation_expression
+%type <expression> simple_name
+%type <expression> parenthesized_expression
+%type <expression> member_access
+%type <expression> invocation_expression
+%type <expression> element_access
+%type <list> expression_list
+%type <expression> this_access
+%type <expression> base_access
+%type <expression> post_increment_expression
+%type <expression> post_decrement_expression
+%type <expression> object_creation_expression
+%type <expression> typeof_expression
+%type <expression> unary_expression
+%type <expression> pre_increment_expression
+%type <expression> pre_decrement_expression
+%type <expression> cast_expression
+%type <expression> pointer_indirection_expression
+%type <expression> addressof_expression
+%type <expression> multiplicative_expression
+%type <expression> additive_expression
+%type <expression> shift_expression
+%type <expression> relational_expression
+%type <expression> equality_expression
+%type <expression> and_expression
+%type <expression> exclusive_or_expression
+%type <expression> inclusive_or_expression
+%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
+%type <expression> expression
+%type <statement> statement
+%type <statement> embedded_statement
+%type <statement> block
+%type <list> opt_statement_list
+%type <list> statement_list
+%type <statement> empty_statement
+%type <statement> declaration_statement
+%type <local_variable_declaration> local_variable_declaration
+%type <type_reference> local_variable_type
+%type <num> opt_op_neg
+%type <statement> expression_statement
+%type <expression> statement_expression
+%type <statement> selection_statement
+%type <statement> if_statement
+%type <statement> switch_statement
+%type <list> switch_block
+%type <list> opt_switch_sections
+%type <list> switch_sections
+%type <switch_section> switch_section
+%type <list> switch_labels
+%type <switch_label> switch_label
+%type <statement> iteration_statement
+%type <statement> while_statement
+%type <statement> do_statement
+%type <statement> for_statement
+%type <list> opt_statement_expression_list
+%type <list> statement_expression_list
+%type <statement> foreach_statement
+%type <statement> jump_statement
+%type <statement> break_statement
+%type <statement> continue_statement
+%type <statement> return_statement
+%type <statement> throw_statement
+%type <statement> try_statement
+%type <list> catch_clauses
+%type <list> specific_catch_clauses
+%type <catch_clause> specific_catch_clause
+%type <catch_clause> opt_general_catch_clause
+%type <catch_clause> general_catch_clause
+%type <statement> opt_finally_clause
+%type <statement> finally_clause
+%type <statement> lock_statement
+%type <namespace> namespace_declaration
+%type <str> opt_name_specifier
+%type <str> name_specifier
+%type <class> class_declaration
+%type <num> opt_access_modifier
+%type <num> access_modifier
+%type <num> opt_modifiers
+%type <num> modifiers
+%type <num> modifier
+%type <list> opt_class_base
+%type <list> class_base
+%type <list> type_list
+%type <property> property_declaration
+%type <property_accessor> get_accessor_declaration
+%type <property_accessor> opt_set_accessor_declaration
+%type <property_accessor> set_accessor_declaration
+%type <struct_> struct_declaration
+%type <struct_> struct_header
+%type <interface> interface_declaration
+%type <enum_> enum_declaration
+%type <list> enum_body
+%type <list> opt_enum_member_declarations
+%type <list> enum_member_declarations
+%type <enum_value> enum_member_declaration
+%type <flags> flags_declaration
+%type <list> flags_body
+%type <list> opt_flags_member_declarations
+%type <list> flags_member_declarations
+%type <flags_value> flags_member_declaration
+%type <callback> callback_declaration
+%type <constant> constant_declaration
+%type <field> field_declaration
+%type <list> variable_declarators
+%type <variable_declarator> variable_declarator
+%type <expression> initializer
+%type <list> opt_variable_initializer_list
+%type <list> variable_initializer_list
+%type <expression> variable_initializer
+%type <method> method_declaration
+%type <method> method_header
+%type <statement> method_body
+%type <list> opt_formal_parameter_list
+%type <list> formal_parameter_list
+%type <num> opt_construct
+%type <list> fixed_parameters
+%type <formal_parameter> fixed_parameter
+%type <list> opt_throws_declaration
+%type <list> throws_declaration
+%type <signal> signal_declaration
+%type <constructor> constructor_declaration
+%type <destructor> destructor_declaration
+%type <list> opt_attributes
+%type <list> attributes
+%type <list> attribute_sections
+%type <list> attribute_section
+%type <list> attribute_list
+%type <attribute> attribute
+%type <str> attribute_name
+%type <list> opt_named_argument_list
+%type <list> named_argument_list
+%type <named_argument> named_argument
+%type <list> opt_type_parameter_list
+%type <list> type_parameter_list
+%type <list> type_parameters
+%type <type_parameter> type_parameter
+%type <list> opt_type_argument_list
+%type <list> type_argument_list
+%type <list> type_arguments
+%type <type_reference> type_argument
+%type <expression> member_name
+
+/* expect shift/reduce conflict on if/else */
+%expect 1
+
+%start compilation_unit
+
+%%
+
+opt_comma
+ : /* empty */
+ | COMMA
+ ;
+
+/* identifiers never conflict with context-specific keywords get or set */
+identifier
+ : IDENTIFIER
+ | GET
+ {
+ $$ = g_strdup ("get");
+ }
+ | SET
+ {
+ $$ = g_strdup ("set");
+ }
+ ;
+
+literal
+ : boolean_literal
+ | INTEGER_LITERAL
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_LITERAL (vala_integer_literal_new ($1, src));
+ g_object_unref (src);
+ g_free ($1);
+ }
+ | REAL_LITERAL
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_LITERAL (vala_real_literal_new ($1, src));
+ g_free ($1);
+ g_object_unref (src);
+ }
+ | CHARACTER_LITERAL
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_LITERAL (vala_character_literal_new ($1, src));
+ g_object_unref (src);
+ g_free ($1);
+ }
+ | STRING_LITERAL
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_LITERAL (vala_string_literal_new ($1, src));
+ g_object_unref (src);
+ g_free ($1);
+ }
+ | VALA_NULL
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_LITERAL (vala_null_literal_new (src));
+ g_object_unref (src);
+ }
+ ;
+
+boolean_literal
+ : VALA_TRUE
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_LITERAL (vala_boolean_literal_new (TRUE, src));
+ g_object_unref (src);
+ }
+ | VALA_FALSE
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_LITERAL (vala_boolean_literal_new (FALSE, src));
+ g_object_unref (src);
+ }
+ ;
+
+compilation_unit
+ : opt_using_directives opt_outer_declarations
+ ;
+
+type_name
+ : identifier opt_type_argument_list
+ {
+ GList *l;
+ ValaSourceReference *src = src(@1);
+ $$ = vala_type_reference_new_from_name (NULL, $1, src);
+ g_free ($1);
+ g_object_unref (src);
+ for (l = $2; l != NULL; l = l->next) {
+ vala_type_reference_add_type_argument ($$, l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($2);
+ }
+ | identifier DOT identifier opt_type_argument_list
+ {
+ GList *l;
+ ValaSourceReference *src = src(@1);
+ $$ = vala_type_reference_new_from_name ($1, $3, src);
+ g_free ($1);
+ g_free ($3);
+ g_object_unref (src);
+ for (l = $4; l != NULL; l = l->next) {
+ vala_type_reference_add_type_argument ($$, l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($4);
+ }
+ ;
+
+stars
+ : STAR
+ {
+ $$ = 1;
+ }
+ | stars STAR
+ {
+ $$ = $1 + 1;
+ }
+ ;
+
+type
+ : type_name opt_rank_specifier opt_op_neg
+ {
+ $$ = $1;
+ vala_type_reference_set_array_rank ($$, $2);
+ if ($3) {
+ vala_type_reference_set_non_null ($$, TRUE);
+ }
+ }
+ | REF type_name opt_rank_specifier opt_op_neg
+ {
+ $$ = $2;
+ vala_type_reference_set_is_ref ($$, TRUE);
+ vala_type_reference_set_array_rank ($$, $3);
+ if ($4) {
+ vala_type_reference_set_non_null ($$, TRUE);
+ }
+ }
+ | WEAK type_name opt_rank_specifier opt_op_neg
+ {
+ $$ = $2;
+ vala_type_reference_set_is_weak ($$, TRUE);
+ vala_type_reference_set_array_rank ($$, $3);
+ if ($4) {
+ vala_type_reference_set_non_null ($$, TRUE);
+ }
+ }
+ | OUT type_name opt_rank_specifier opt_op_neg
+ {
+ $$ = $2;
+ vala_type_reference_set_is_out ($$, TRUE);
+ vala_type_reference_set_array_rank ($$, $3);
+ if ($4) {
+ vala_type_reference_set_non_null ($$, TRUE);
+ }
+ }
+ | OUT REF type_name opt_rank_specifier opt_op_neg
+ {
+ $$ = $3;
+ vala_type_reference_set_is_ref ($$, TRUE);
+ vala_type_reference_set_is_out ($$, TRUE);
+ vala_type_reference_set_array_rank ($$, $4);
+ if ($5) {
+ vala_type_reference_set_non_null ($$, TRUE);
+ }
+ }
+ | type_name stars opt_rank_specifier opt_op_neg
+ {
+ $$ = $1;
+ vala_type_reference_set_pointer_level ($$, $2);
+ vala_type_reference_set_array_rank ($$, $3);
+ if ($4) {
+ vala_type_reference_set_non_null ($$, TRUE);
+ }
+ }
+ ;
+
+opt_argument_list
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | argument_list
+ ;
+
+argument_list
+ : argument
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | argument_list COMMA argument
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+argument
+ : expression
+ ;
+
+primary_expression
+ : primary_no_array_creation_expression
+ | array_creation_expression
+ ;
+
+array_creation_expression
+ : NEW member_name size_specifier_list opt_initializer
+ {
+ GList *l;
+ ValaSourceReference *src = src(@2);
+ ValaTypeReference *t = vala_type_reference_new_from_expression (VALA_EXPRESSION ($2));
+ $$ = VALA_EXPRESSION (vala_array_creation_expression_new (t, g_list_length ($3), VALA_INITIALIZER_LIST ($4), src));
+ g_object_unref (t);
+ for (l = $3; l != NULL; l = l->next) {
+ vala_array_creation_expression_append_size (VALA_ARRAY_CREATION_EXPRESSION ($$), VALA_EXPRESSION (l->data));
+ g_object_unref (l->data);
+ }
+ g_list_free ($3);
+ g_object_unref (src);
+ g_object_unref ($2);
+ if ($4 != NULL) {
+ g_object_unref ($4);
+ }
+ }
+ | NEW member_name rank_specifier initializer
+ {
+ ValaSourceReference *src = src(@2);
+ ValaTypeReference *t = vala_type_reference_new_from_expression (VALA_EXPRESSION ($2));
+ $$ = VALA_EXPRESSION (vala_array_creation_expression_new (t, $3, VALA_INITIALIZER_LIST ($4), src));
+ g_object_unref (t);
+ g_object_unref (src);
+ g_object_unref ($2);
+ g_object_unref ($4);
+ }
+ ;
+
+size_specifier_list
+ : OPEN_BRACKET expression_list CLOSE_BRACKET
+ {
+ $$ = $2;
+ }
+ ;
+
+opt_initializer
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | initializer
+ ;
+
+opt_rank_specifier
+ : /* empty */
+ {
+ $$ = 0;
+ }
+ | rank_specifier
+ ;
+
+rank_specifier
+ : OPEN_BRACKET opt_comma_list CLOSE_BRACKET
+ {
+ $$ = $2;
+ }
+ | bracket_pair
+ ;
+
+opt_bracket_pair
+ : /* empty */
+ {
+ $$ = 0;
+ }
+ | bracket_pair
+ ;
+
+bracket_pair
+ : BRACKET_PAIR
+ {
+ $$ = 1;
+ }
+ ;
+
+opt_comma_list
+ : /* empty */
+ {
+ $$ = 1;
+ }
+ | comma_list
+ ;
+
+comma_list
+ : COMMA
+ {
+ $$ = 1;
+ }
+ | comma_list COMMA
+ {
+ $$ = $1 + 1;
+ }
+ ;
+
+primary_no_array_creation_expression
+ : literal
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_literal_expression_new ($1, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ }
+ | simple_name
+ | parenthesized_expression
+ | member_access
+ | invocation_expression
+ | element_access
+ | this_access
+ | base_access
+ | post_increment_expression
+ | post_decrement_expression
+ | object_creation_expression
+ | typeof_expression
+ ;
+
+simple_name
+ : identifier opt_type_argument_list
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_member_access_new (NULL, $1, src));
+ g_free ($1);
+ g_object_unref (src);
+
+ if ($2 != NULL) {
+ GList *l;
+ for (l = $2; l != NULL; l = l->next) {
+ vala_member_access_add_type_argument (VALA_MEMBER_ACCESS ($$), l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($2);
+ }
+ }
+ ;
+
+parenthesized_expression
+ : OPEN_PARENS expression CLOSE_PARENS
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_parenthesized_expression_new ($2, src));
+ g_object_unref (src);
+ g_object_unref ($2);
+ }
+ ;
+
+member_access
+ : primary_expression DOT identifier opt_type_argument_list
+ {
+ ValaSourceReference *src = src(@3);
+ $$ = VALA_EXPRESSION (vala_member_access_new ($1, $3, src));
+ g_object_unref ($1);
+ g_free ($3);
+ g_object_unref (src);
+
+ if ($4 != NULL) {
+ GList *l;
+ for (l = $4; l != NULL; l = l->next) {
+ vala_member_access_add_type_argument (VALA_MEMBER_ACCESS ($$), l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($4);
+ }
+ }
+ ;
+
+invocation_expression
+ : primary_expression open_parens opt_argument_list CLOSE_PARENS
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_invocation_expression_new ($1, src));
+ g_object_unref ($1);
+ g_object_unref (src);
+
+ if ($3 != NULL) {
+ GList *l;
+ for (l = $3; l != NULL; l = l->next) {
+ vala_invocation_expression_add_argument (VALA_INVOCATION_EXPRESSION ($$), l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($3);
+ }
+ }
+ ;
+
+element_access
+ : primary_no_array_creation_expression OPEN_BRACKET expression_list CLOSE_BRACKET
+ {
+ GList *l;
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_element_access_new ($1, src));
+ for (l = $3; l != NULL; l = l->next) {
+ vala_element_access_append_index (VALA_ELEMENT_ACCESS ($$), VALA_EXPRESSION (l->data));
+ g_object_unref (l->data);
+ }
+ g_list_free ($3);
+ g_object_unref ($1);
+ g_object_unref (src);
+ }
+ ;
+
+expression_list
+ : expression
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | expression_list COMMA expression
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+this_access
+ : THIS
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_member_access_new (NULL, "this", src));
+ g_object_unref (src);
+ }
+ ;
+
+base_access
+ : BASE
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_base_access_new (src));
+ g_object_unref (src);
+ }
+ ;
+
+post_increment_expression
+ : primary_expression OP_INC
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_postfix_expression_new ($1, TRUE, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ }
+ ;
+
+post_decrement_expression
+ : primary_expression OP_DEC
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_postfix_expression_new ($1, FALSE, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ }
+ ;
+
+object_creation_expression
+ : NEW member_name open_parens opt_argument_list CLOSE_PARENS
+ {
+ ValaSourceReference *src = src(@2);
+ ValaObjectCreationExpression *expr = vala_object_creation_expression_new (VALA_MEMBER_ACCESS ($2), src);
+ g_object_unref ($2);
+ g_object_unref (src);
+
+ if ($4 != NULL) {
+ GList *l;
+ for (l = $4; l != NULL; l = l->next) {
+ vala_object_creation_expression_add_argument (expr, l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($4);
+ }
+
+ $$ = VALA_EXPRESSION (expr);
+ }
+ ;
+
+typeof_expression
+ : TYPEOF open_parens type_name CLOSE_PARENS
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_typeof_expression_new ($3, src));
+ g_object_unref ($3);
+ g_object_unref (src);
+ }
+
+unary_expression
+ : primary_expression
+ | PLUS unary_expression
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_PLUS, $2, src));
+ g_object_unref (src);
+ g_object_unref ($2);
+ }
+ | MINUS unary_expression
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_MINUS, $2, src));
+ g_object_unref (src);
+ g_object_unref ($2);
+ }
+ | OP_NEG unary_expression
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_LOGICAL_NEGATION, $2, src));
+ g_object_unref (src);
+ g_object_unref ($2);
+ }
+ | TILDE unary_expression
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_BITWISE_COMPLEMENT, $2, src));
+ g_object_unref (src);
+ g_object_unref ($2);
+ }
+ | pre_increment_expression
+ | pre_decrement_expression
+ | REF unary_expression
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_REF, $2, src));
+ g_object_unref (src);
+ g_object_unref ($2);
+ }
+ | OUT unary_expression
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_OUT, $2, src));
+ g_object_unref (src);
+ g_object_unref ($2);
+ }
+ | HASH unary_expression
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_reference_transfer_expression_new ($2, src));
+ g_object_unref (src);
+ g_object_unref ($2);
+ }
+ | cast_expression
+ | pointer_indirection_expression
+ | addressof_expression
+ ;
+
+pre_increment_expression
+ : OP_INC unary_expression
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_INCREMENT, $2, src));
+ g_object_unref ($2);
+ g_object_unref (src);
+ }
+ ;
+
+pre_decrement_expression
+ : OP_DEC unary_expression
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_DECREMENT, $2, src));
+ g_object_unref ($2);
+ g_object_unref (src);
+ }
+ ;
+
+cast_expression
+ : OPEN_CAST_PARENS type CLOSE_PARENS unary_expression
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_cast_expression_new ($4, $2, src));
+ g_object_unref (src);
+ g_object_unref ($2);
+ g_object_unref ($4);
+ }
+ ;
+
+pointer_indirection_expression
+ : STAR unary_expression
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_pointer_indirection_new ($2, src));
+ g_object_unref (src);
+ g_object_unref ($2);
+ }
+ ;
+
+addressof_expression
+ : BITWISE_AND unary_expression
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_addressof_expression_new ($2, src));
+ g_object_unref (src);
+ g_object_unref ($2);
+ }
+ ;
+
+multiplicative_expression
+ : unary_expression
+ | multiplicative_expression STAR unary_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_MUL, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ | multiplicative_expression DIV unary_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_DIV, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ | multiplicative_expression PERCENT unary_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_MOD, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ ;
+
+additive_expression
+ : multiplicative_expression
+ | additive_expression PLUS multiplicative_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_PLUS, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ | additive_expression MINUS multiplicative_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_MINUS, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ ;
+
+shift_expression
+ : additive_expression
+ | shift_expression OP_SHIFT_LEFT additive_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_SHIFT_LEFT, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ /* don't use two OP_GT due to resolve parse conflicts
+ * stacked generics won't be that common in vala */
+ | shift_expression OP_SHIFT_RIGHT additive_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_SHIFT_RIGHT, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ ;
+
+relational_expression
+ : shift_expression
+ | relational_expression OP_LT shift_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_LESS_THAN, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ | relational_expression OP_GT shift_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_GREATER_THAN, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ | relational_expression OP_LE shift_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_LESS_THAN_OR_EQUAL, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ | relational_expression OP_GE shift_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_GREATER_THAN_OR_EQUAL, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ | relational_expression IS type
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_type_check_new ($1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ ;
+
+equality_expression
+ : relational_expression
+ | equality_expression OP_EQ relational_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_EQUALITY, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ | equality_expression OP_NE relational_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_INEQUALITY, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ ;
+
+and_expression
+ : equality_expression
+ | and_expression BITWISE_AND equality_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_BITWISE_AND, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ ;
+
+exclusive_or_expression
+ : and_expression
+ | exclusive_or_expression CARRET and_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_BITWISE_XOR, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ ;
+
+inclusive_or_expression
+ : exclusive_or_expression
+ | inclusive_or_expression BITWISE_OR exclusive_or_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_BITWISE_OR, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ ;
+
+conditional_and_expression
+ : inclusive_or_expression
+ | conditional_and_expression OP_AND inclusive_or_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_AND, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ ;
+
+conditional_or_expression
+ : conditional_and_expression
+ | conditional_or_expression OP_OR conditional_and_expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_binary_expression_new (VALA_BINARY_OPERATOR_OR, $1, $3, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ ;
+
+conditional_expression
+ : conditional_or_expression
+ | conditional_or_expression INTERR expression COLON expression
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_conditional_expression_new ($1, $3, $5, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ g_object_unref ($5);
+ }
+ ;
+
+lambda_expression
+ : OPEN_PARENS opt_lambda_parameter_list CLOSE_PARENS LAMBDA expression
+ {
+ ValaSourceReference *src = src(@4);
+ $$ = VALA_EXPRESSION (vala_lambda_expression_new ($5, src));
+ if ($2 != NULL) {
+ GList *l;
+ for (l = $2; l != NULL; l = l->next) {
+ vala_lambda_expression_add_parameter (VALA_LAMBDA_EXPRESSION ($$), l->data);
+ g_free (l->data);
+ }
+ 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 ($3, src));
+ g_object_unref ($3);
+ g_object_unref (src);
+ vala_lambda_expression_add_parameter (VALA_LAMBDA_EXPRESSION ($$), $1);
+ g_free ($1);
+ }
+ | OPEN_PARENS opt_lambda_parameter_list CLOSE_PARENS LAMBDA block
+ {
+ ValaSourceReference *src = src(@4);
+ $$ = VALA_EXPRESSION (vala_lambda_expression_new_with_statement_body (VALA_BLOCK ($5), src));
+ if ($2 != NULL) {
+ GList *l;
+ for (l = $2; l != NULL; l = l->next) {
+ vala_lambda_expression_add_parameter (VALA_LAMBDA_EXPRESSION ($$), l->data);
+ g_free (l->data);
+ }
+ g_list_free ($2);
+ }
+ g_object_unref ($5);
+ g_object_unref (src);
+ }
+ | identifier LAMBDA block
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_lambda_expression_new_with_statement_body (VALA_BLOCK ($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
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = VALA_EXPRESSION (vala_assignment_new ($1, $3, $2, src));
+ g_object_unref (src);
+ g_object_unref ($1);
+ g_object_unref ($3);
+ }
+ ;
+
+assignment_operator
+ : ASSIGN
+ {
+ $$ = VALA_ASSIGNMENT_OPERATOR_SIMPLE;
+ }
+ | ASSIGN_BITWISE_OR
+ {
+ $$ = VALA_ASSIGNMENT_OPERATOR_BITWISE_OR;
+ }
+ | ASSIGN_BITWISE_AND
+ {
+ $$ = VALA_ASSIGNMENT_OPERATOR_BITWISE_AND;
+ }
+ | ASSIGN_BITWISE_XOR
+ {
+ $$ = VALA_ASSIGNMENT_OPERATOR_BITWISE_XOR;
+ }
+ | ASSIGN_ADD
+ {
+ $$ = VALA_ASSIGNMENT_OPERATOR_ADD;
+ }
+ | ASSIGN_SUB
+ {
+ $$ = VALA_ASSIGNMENT_OPERATOR_SUB;
+ }
+ | ASSIGN_MUL
+ {
+ $$ = VALA_ASSIGNMENT_OPERATOR_MUL;
+ }
+ | ASSIGN_DIV
+ {
+ $$ = VALA_ASSIGNMENT_OPERATOR_DIV;
+ }
+ | ASSIGN_PERCENT
+ {
+ $$ = VALA_ASSIGNMENT_OPERATOR_PERCENT;
+ }
+ | ASSIGN_SHIFT_LEFT
+ {
+ $$ = VALA_ASSIGNMENT_OPERATOR_SHIFT_LEFT;
+ }
+ | ASSIGN_SHIFT_RIGHT
+ {
+ $$ = VALA_ASSIGNMENT_OPERATOR_SHIFT_RIGHT;
+ }
+ ;
+
+opt_expression
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | expression
+ ;
+
+expression
+ : conditional_expression
+ | lambda_expression
+ | assignment
+ | error
+ {
+ $$ = NULL;
+ }
+ ;
+
+statement
+ : declaration_statement
+ | block
+ | empty_statement
+ | expression_statement
+ | selection_statement
+ | iteration_statement
+ | jump_statement
+ | try_statement
+ | lock_statement
+ ;
+
+embedded_statement
+ : block
+ | empty_statement
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_block_new (src));
+ vala_block_add_statement (VALA_BLOCK ($$), $1);
+ g_object_unref ($1);
+ g_object_unref (src);
+ }
+ | expression_statement
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_block_new (src));
+ vala_block_add_statement (VALA_BLOCK ($$), $1);
+ g_object_unref ($1);
+ g_object_unref (src);
+ }
+ | selection_statement
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_block_new (src));
+ vala_block_add_statement (VALA_BLOCK ($$), $1);
+ g_object_unref ($1);
+ g_object_unref (src);
+ }
+ | iteration_statement
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_block_new (src));
+ vala_block_add_statement (VALA_BLOCK ($$), $1);
+ g_object_unref ($1);
+ g_object_unref (src);
+ }
+ | jump_statement
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_block_new (src));
+ vala_block_add_statement (VALA_BLOCK ($$), $1);
+ g_object_unref ($1);
+ g_object_unref (src);
+ }
+ | try_statement
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_block_new (src));
+ vala_block_add_statement (VALA_BLOCK ($$), $1);
+ g_object_unref ($1);
+ g_object_unref (src);
+ }
+ | lock_statement
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_block_new (src));
+ vala_block_add_statement (VALA_BLOCK ($$), $1);
+ g_object_unref ($1);
+ g_object_unref (src);
+ }
+ ;
+
+block
+ : OPEN_BRACE opt_statement_list CLOSE_BRACE
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_block_new (src));
+ if ($2 != NULL) {
+ GList *l;
+ for (l = $2; l != NULL; l = l->next) {
+ vala_block_add_statement (VALA_BLOCK ($$), l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($2);
+ }
+ g_object_unref (src);
+ }
+ ;
+
+opt_statement_list
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | statement_list
+ ;
+
+statement_list
+ : statement
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | statement_list statement
+ {
+ $$ = g_list_append ($1, $2);
+ }
+ ;
+
+empty_statement
+ : SEMICOLON
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_empty_statement_new (src));
+ g_object_unref (src);
+ }
+ ;
+
+declaration_statement
+ : comment local_variable_declaration SEMICOLON
+ {
+ ValaSourceReference *src = src_com(@2, $1);
+ $$ = VALA_STATEMENT (vala_declaration_statement_new ($2, src));
+ g_object_unref (src);
+ g_object_unref ($2);
+ }
+ ;
+
+local_variable_declaration
+ : local_variable_type variable_declarators
+ {
+ GList *l;
+ ValaSourceReference *src = src(@2);
+ $$ = vala_local_variable_declaration_new ($1, src);
+ g_object_unref (src);
+ for (l = $2; l != NULL; l = l->next) {
+ ValaVariableDeclarator *decl = l->data;
+ ValaTypeReference *type = vala_type_reference_copy ($1);
+ vala_variable_declarator_set_type_reference (decl, type);
+ g_object_unref (type);
+ vala_local_variable_declaration_add_declarator ($$, decl);
+ g_object_unref (decl);
+ }
+ g_list_free ($2);
+ g_object_unref ($1);
+ }
+ | VAR variable_declarators
+ {
+ GList *l;
+ ValaSourceReference *src = src(@2);
+ $$ = vala_local_variable_declaration_new_var_type (src);
+ g_object_unref (src);
+ for (l = $2; l != NULL; l = l->next) {
+ vala_local_variable_declaration_add_declarator ($$, l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($2);
+ }
+ ;
+
+/* don't use type to prevent reduce/reduce conflict */
+local_variable_type
+ : primary_expression opt_bracket_pair opt_op_neg
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = vala_type_reference_new_from_expression ($1);
+ g_object_unref ($1);
+ g_object_unref (src);
+ vala_type_reference_set_takes_ownership ($$, TRUE);
+ vala_type_reference_set_array_rank ($$, $2);
+ if ($3) {
+ vala_type_reference_set_non_null ($$, TRUE);
+ }
+ }
+ | primary_expression stars
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = vala_type_reference_new_from_expression ($1);
+ g_object_unref ($1);
+ g_object_unref (src);
+ vala_type_reference_set_pointer_level ($$, $2);
+ }
+ | REF primary_expression opt_bracket_pair opt_op_neg
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = vala_type_reference_new_from_expression ($2);
+ g_object_unref ($2);
+ g_object_unref (src);
+ vala_type_reference_set_takes_ownership ($$, TRUE);
+ vala_type_reference_set_array_rank ($$, $3);
+ if ($4) {
+ vala_type_reference_set_non_null ($$, TRUE);
+ }
+ }
+ | WEAK primary_expression opt_bracket_pair opt_op_neg
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = vala_type_reference_new_from_expression ($2);
+ g_object_unref ($2);
+ g_object_unref (src);
+ vala_type_reference_set_array_rank ($$, $3);
+ if ($4) {
+ vala_type_reference_set_non_null ($$, TRUE);
+ }
+ }
+ ;
+
+opt_op_neg
+ : /* empty */
+ {
+ $$ = FALSE;
+ }
+ | OP_NEG
+ {
+ $$ = TRUE;
+ }
+ ;
+
+expression_statement
+ : comment statement_expression SEMICOLON
+ {
+ ValaSourceReference *src = src_com(@2, $1);
+ $$ = VALA_STATEMENT (vala_expression_statement_new ($2, src));
+ g_object_unref (src);
+ g_object_unref ($2);
+ }
+ ;
+
+statement_expression
+ : invocation_expression
+ | object_creation_expression
+ | assignment
+ | post_increment_expression
+ | post_decrement_expression
+ | pre_increment_expression
+ | pre_decrement_expression
+ ;
+
+selection_statement
+ : if_statement
+ | switch_statement
+ ;
+
+if_statement
+ : comment IF open_parens expression CLOSE_PARENS embedded_statement
+ {
+ ValaBlock *true_block;
+ if (VALA_IS_BLOCK ($6)) {
+ true_block = VALA_BLOCK ($6);
+ } else {
+ true_block = vala_block_new (vala_code_node_get_source_reference (VALA_CODE_NODE ($6)));
+ vala_block_add_statement (true_block, $6);
+ g_object_unref ($6);
+ }
+
+ ValaSourceReference *src = src_com(@4, $1);
+ $$ = VALA_STATEMENT (vala_if_statement_new ($4, true_block, NULL, src));
+ g_object_unref (src);
+ g_object_unref ($4);
+ g_object_unref (true_block);
+ }
+ | comment IF open_parens expression CLOSE_PARENS embedded_statement ELSE embedded_statement
+ {
+ ValaBlock *true_block;
+ if (VALA_IS_BLOCK ($6)) {
+ true_block = VALA_BLOCK ($6);
+ } else {
+ true_block = vala_block_new (vala_code_node_get_source_reference (VALA_CODE_NODE ($6)));
+ vala_block_add_statement (true_block, $6);
+ g_object_unref ($6);
+ }
+
+ ValaBlock *false_block;
+ if (VALA_IS_BLOCK ($8)) {
+ false_block = VALA_BLOCK ($8);
+ } else {
+ false_block = vala_block_new (vala_code_node_get_source_reference (VALA_CODE_NODE ($8)));
+ vala_block_add_statement (false_block, $8);
+ g_object_unref ($8);
+ }
+
+ ValaSourceReference *src = src_com(@4, $1);
+ $$ = VALA_STATEMENT (vala_if_statement_new ($4, true_block, false_block, src));
+ g_object_unref (src);
+ g_object_unref ($4);
+ g_object_unref (true_block);
+ g_object_unref (false_block);
+ }
+ ;
+
+switch_statement
+ : comment SWITCH open_parens expression CLOSE_PARENS switch_block
+ {
+ ValaSourceReference *src = src_com(@4, $1);
+ $$ = VALA_STATEMENT (vala_switch_statement_new ($4, src));
+ g_object_unref ($4);
+ g_object_unref (src);
+
+ if ($6 != NULL) {
+ GList *l;
+ for (l = $6; l != NULL; l = l->next) {
+ vala_switch_statement_add_section (VALA_SWITCH_STATEMENT ($$), l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($6);
+ }
+ }
+ ;
+
+switch_block
+ : OPEN_BRACE opt_switch_sections CLOSE_BRACE
+ {
+ $$ = $2;
+ }
+ ;
+
+opt_switch_sections
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | switch_sections
+ ;
+
+switch_sections
+ : switch_section
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | switch_sections switch_section
+ {
+ $$ = g_list_append ($1, $2);
+ }
+ ;
+
+switch_section
+ : comment switch_labels statement_list
+ {
+ ValaSourceReference *src = src_com(@2, $1);
+ $$ = vala_switch_section_new (src);
+ g_object_unref (src);
+
+ GList *l;
+ for (l = $2; l != NULL; l = l->next) {
+ vala_switch_section_add_label ($$, l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($2);
+ for (l = $3; l != NULL; l = l->next) {
+ vala_switch_section_add_statement ($$, l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($3);
+ }
+ ;
+
+switch_labels
+ : switch_label
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | switch_labels switch_label
+ {
+ $$ = g_list_append ($1, $2);
+ }
+ ;
+
+switch_label
+ : CASE expression COLON
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = vala_switch_label_new ($2, src);
+ g_object_unref ($2);
+ g_object_unref (src);
+ }
+ | DEFAULT COLON
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = vala_switch_label_new_with_default (src);
+ g_object_unref (src);
+ }
+ ;
+
+iteration_statement
+ : while_statement
+ | do_statement
+ | for_statement
+ | foreach_statement
+ ;
+
+while_statement
+ : WHILE open_parens expression CLOSE_PARENS embedded_statement
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_while_statement_new ($3, $5, src));
+ g_object_unref (src);
+ g_object_unref ($3);
+ g_object_unref ($5);
+ }
+ ;
+
+do_statement
+ : DO embedded_statement WHILE open_parens expression CLOSE_PARENS SEMICOLON
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_do_statement_new ($2, $5, src));
+ g_object_unref ($2);
+ g_object_unref ($5);
+ g_object_unref (src);
+ }
+ ;
+
+for_statement
+ : FOR OPEN_PARENS opt_statement_expression_list SEMICOLON opt_expression SEMICOLON opt_statement_expression_list CLOSE_PARENS embedded_statement
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_for_statement_new ($5, $9, src));
+ if ($5 != NULL) {
+ g_object_unref ($5);
+ }
+ g_object_unref ($9);
+ g_object_unref (src);
+
+ GList *l;
+ if ($3 != NULL) {
+ for (l = $3; l != NULL; l = l->next) {
+ vala_for_statement_add_initializer (VALA_FOR_STATEMENT ($$), l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($3);
+ }
+ if ($7 != NULL) {
+ for (l = $7; l != NULL; l = l->next) {
+ vala_for_statement_add_iterator (VALA_FOR_STATEMENT ($$), l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($7);
+ }
+ }
+ | FOR OPEN_PARENS local_variable_declaration SEMICOLON opt_expression SEMICOLON opt_statement_expression_list CLOSE_PARENS embedded_statement
+ {
+ ValaSourceReference *src = src(@1);
+
+ ValaBlock *block = vala_block_new (src);
+
+ ValaForStatement *for_statement = vala_for_statement_new ($5, $9, src);
+ if ($5 != NULL) {
+ g_object_unref ($5);
+ }
+ g_object_unref ($9);
+
+ GList *l;
+
+ GList* decls = vala_local_variable_declaration_get_variable_declarators ($3);
+ for (l = decls; l != NULL; l = l->next) {
+ ValaVariableDeclarator *decl = l->data;
+ ValaExpression *init = vala_variable_declarator_get_initializer (decl);
+
+ if (init != NULL) {
+ ValaSourceReference *decl_src = vala_code_node_get_source_reference (VALA_CODE_NODE (decl));
+ ValaMemberAccess *lhs = vala_member_access_new (NULL, vala_variable_declarator_get_name (decl), decl_src);
+ ValaAssignment *assign = vala_assignment_new (VALA_EXPRESSION (lhs), init, VALA_ASSIGNMENT_OPERATOR_SIMPLE, decl_src);
+ g_object_unref (lhs);
+ vala_for_statement_add_initializer (for_statement, VALA_EXPRESSION (assign));
+ g_object_unref (assign);
+
+ vala_variable_declarator_set_initializer (decl, NULL);
+ }
+ }
+ g_list_free (decls);
+
+ ValaDeclarationStatement *decl_statement = vala_declaration_statement_new ($3, src);
+ g_object_unref ($3);
+ g_object_unref (src);
+ vala_block_add_statement (block, VALA_STATEMENT (decl_statement));
+ g_object_unref (decl_statement);
+
+ if ($7 != NULL) {
+ for (l = $7; l != NULL; l = l->next) {
+ vala_for_statement_add_iterator (for_statement, l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($7);
+ }
+
+ vala_block_add_statement (block, VALA_STATEMENT (for_statement));
+
+ $$ = VALA_STATEMENT (block);
+ }
+ ;
+
+opt_statement_expression_list
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | statement_expression_list
+ ;
+
+statement_expression_list
+ : statement_expression
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | statement_expression_list COMMA statement_expression
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+foreach_statement
+ : FOREACH OPEN_PARENS type identifier IN expression CLOSE_PARENS embedded_statement
+ {
+ ValaSourceReference *src = src(@3);
+ $$ = VALA_STATEMENT (vala_foreach_statement_new ($3, $4, $6, $8, src));
+ g_object_unref ($3);
+ g_free ($4);
+ g_object_unref ($6);
+ g_object_unref ($8);
+ g_object_unref (src);
+ }
+ ;
+
+jump_statement
+ : break_statement
+ | continue_statement
+ | return_statement
+ | throw_statement
+ ;
+
+break_statement
+ : BREAK SEMICOLON
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_break_statement_new (src));
+ g_object_unref (src);
+ }
+ ;
+
+continue_statement
+ : CONTINUE SEMICOLON
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_continue_statement_new (src));
+ g_object_unref (src);
+ }
+ ;
+
+return_statement
+ : RETURN opt_expression SEMICOLON
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_return_statement_new ($2, src));
+ g_object_unref (src);
+ if ($2 != NULL) {
+ g_object_unref ($2);
+ }
+ }
+ ;
+
+throw_statement
+ : THROW expression SEMICOLON
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_throw_statement_new ($2, src));
+ g_object_unref (src);
+ if ($2 != NULL) {
+ g_object_unref ($2);
+ }
+ }
+ ;
+
+try_statement
+ : TRY block catch_clauses opt_finally_clause
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_try_statement_new (VALA_BLOCK ($2), VALA_BLOCK ($4), src));
+ g_object_unref ($2);
+ if ($4 != NULL) {
+ g_object_unref ($4);
+ }
+ g_object_unref (src);
+
+ GList *l;
+ for (l = $3; l != NULL; l = l->next) {
+ vala_try_statement_add_catch_clause (VALA_TRY_STATEMENT ($$), l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($3);
+ }
+ | TRY block finally_clause
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_STATEMENT (vala_try_statement_new (VALA_BLOCK ($2), VALA_BLOCK ($3), src));
+ g_object_unref ($2);
+ g_object_unref ($3);
+ g_object_unref (src);
+ }
+ ;
+
+catch_clauses
+ : specific_catch_clauses opt_general_catch_clause
+ {
+ if ($2 != NULL) {
+ $$ = g_list_append ($1, $2);
+ } else {
+ $$ = $1;
+ }
+ }
+ | general_catch_clause
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ ;
+
+specific_catch_clauses
+ : specific_catch_clause
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | specific_catch_clauses specific_catch_clause
+ {
+ $$ = g_list_append ($1, $2);
+ }
+ ;
+
+specific_catch_clause
+ : CATCH OPEN_PARENS type identifier CLOSE_PARENS block
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = vala_catch_clause_new ($3, $4, VALA_BLOCK ($6), src);
+ g_object_unref ($3);
+ g_free ($4);
+ g_object_unref ($6);
+ g_object_unref (src);
+ }
+ ;
+
+opt_general_catch_clause
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | general_catch_clause
+ ;
+
+general_catch_clause
+ : CATCH block
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = vala_catch_clause_new (NULL, NULL, VALA_BLOCK ($2), src);
+ g_object_unref ($2);
+ g_object_unref (src);
+ }
+ ;
+opt_finally_clause
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | finally_clause
+ ;
+
+
+finally_clause
+ : FINALLY block
+ {
+ $$ = $2;
+ }
+ ;
+
+lock_statement
+ : comment LOCK OPEN_PARENS expression CLOSE_PARENS embedded_statement
+ {
+ ValaSourceReference *src = src_com(@4, $1);
+ $$ = VALA_STATEMENT (vala_lock_statement_new ($4, $6, src));
+ g_object_unref (src);
+ g_object_unref ($4);
+ g_object_unref ($6);
+ }
+
+namespace_declaration
+ : comment opt_attributes NAMESPACE identifier
+ {
+ ValaSourceReference *src = src_com(@4, $1);
+ current_namespace = vala_namespace_new ($4, src);
+ g_object_unref (src);
+ VALA_CODE_NODE(current_namespace)->attributes = $2;
+ g_free ($4);
+ }
+ namespace_body
+ {
+ $$ = current_namespace;
+ current_namespace = vala_source_file_get_global_namespace (current_source_file);
+ }
+ ;
+
+namespace_body
+ : OPEN_BRACE opt_namespace_member_declarations CLOSE_BRACE
+ | OPEN_BRACE error CLOSE_BRACE
+ ;
+
+opt_name_specifier
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | name_specifier
+ ;
+
+name_specifier
+ : DOT identifier
+ {
+ $$ = $2;
+ }
+ ;
+
+opt_using_directives
+ : /* empty */
+ | using_directives
+ ;
+
+using_directives
+ : using_directive
+ | using_directives using_directive
+ ;
+
+using_directive
+ : USING identifier SEMICOLON
+ {
+ ValaSourceReference *src = src(@2);
+ ValaNamespaceReference *ns_ref = vala_namespace_reference_new ($2, src);
+ g_object_unref (src);
+ g_free ($2);
+ vala_source_file_add_using_directive (current_source_file, ns_ref);
+ g_object_unref (ns_ref);
+ }
+ ;
+
+opt_outer_declarations
+ : /* empty */
+ | outer_declarations
+ ;
+
+outer_declarations
+ : outer_declaration
+ | outer_declarations outer_declaration
+ ;
+
+outer_declaration
+ : namespace_declaration
+ {
+ vala_source_file_add_namespace (current_source_file, $1);
+ g_object_unref ($1);
+ }
+ | namespace_member_declaration
+ ;
+
+opt_namespace_member_declarations
+ : /* empty */
+ | namespace_member_declarations
+ ;
+
+namespace_member_declarations
+ : namespace_member_declaration
+ | namespace_member_declarations namespace_member_declaration
+ ;
+
+namespace_member_declaration
+ : class_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_namespace_add_class (current_namespace, $1);
+ g_object_unref ($1);
+ }
+
+ if (current_namespace_implicit) {
+ /* current namespace has been declared implicitly */
+ current_namespace = vala_source_file_get_global_namespace (current_source_file);
+ current_namespace_implicit = FALSE;
+ }
+ }
+ | struct_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_namespace_add_struct (current_namespace, $1);
+ g_object_unref ($1);
+ }
+
+ if (current_namespace_implicit) {
+ /* current namespace has been declared implicitly */
+ current_namespace = vala_source_file_get_global_namespace (current_source_file);
+ current_namespace_implicit = FALSE;
+ }
+ }
+ | interface_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_namespace_add_interface (current_namespace, $1);
+ g_object_unref ($1);
+ }
+
+ if (current_namespace_implicit) {
+ /* current namespace has been declared implicitly */
+ current_namespace = vala_source_file_get_global_namespace (current_source_file);
+ current_namespace_implicit = FALSE;
+ }
+ }
+ | enum_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_namespace_add_enum (current_namespace, $1);
+ g_object_unref ($1);
+ }
+
+ if (current_namespace_implicit) {
+ /* current namespace has been declared implicitly */
+ current_namespace = vala_source_file_get_global_namespace (current_source_file);
+ current_namespace_implicit = FALSE;
+ }
+ }
+ | flags_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_namespace_add_flags (current_namespace, $1);
+ g_object_unref ($1);
+ }
+
+ if (current_namespace_implicit) {
+ /* current namespace has been declared implicitly */
+ current_namespace = vala_source_file_get_global_namespace (current_source_file);
+ current_namespace_implicit = FALSE;
+ }
+ }
+ | callback_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_namespace_add_callback (current_namespace, $1);
+ g_object_unref ($1);
+ }
+
+ if (current_namespace_implicit) {
+ /* current namespace has been declared implicitly */
+ current_namespace = vala_source_file_get_global_namespace (current_source_file);
+ current_namespace_implicit = FALSE;
+ }
+ }
+ | constant_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_namespace_add_constant (current_namespace, $1);
+ g_object_unref ($1);
+ }
+ }
+ | field_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ /* field must be static, don't require developer
+ * to explicitly state it */
+ vala_field_set_instance ($1, FALSE);
+
+ vala_namespace_add_field (current_namespace, $1);
+ g_object_unref ($1);
+ }
+ }
+ | method_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ /* method must be static, don't require developer
+ * to explicitly state it */
+ vala_method_set_instance ($1, FALSE);
+
+ vala_namespace_add_method (current_namespace, $1);
+ g_object_unref ($1);
+ }
+ }
+ ;
+
+class_declaration
+ : comment opt_attributes opt_access_modifier opt_modifiers CLASS identifier opt_name_specifier opt_type_parameter_list opt_class_base
+ {
+ char *name = $6;
+
+ if ($7 != NULL) {
+ ValaSourceReference *ns_src = src(@6);
+ current_namespace = vala_namespace_new ($6, ns_src);
+ g_free ($6);
+ g_object_unref (ns_src);
+ current_namespace_implicit = TRUE;
+
+ vala_source_file_add_namespace (current_source_file, current_namespace);
+ g_object_unref (current_namespace);
+
+ name = $7;
+ }
+
+ GList *l;
+ ValaSourceReference *src = src_com(@6, $1);
+ current_class = vala_class_new (name, src);
+ g_free (name);
+ g_object_unref (src);
+
+ VALA_CODE_NODE(current_class)->attributes = $2;
+ if ($3 != 0) {
+ VALA_DATA_TYPE(current_class)->access = $3;
+ }
+ if (($4 & VALA_MODIFIER_ABSTRACT) == VALA_MODIFIER_ABSTRACT) {
+ vala_class_set_is_abstract (current_class, TRUE);
+ }
+ if (($4 & VALA_MODIFIER_STATIC) == VALA_MODIFIER_STATIC) {
+ vala_class_set_is_static (current_class, TRUE);
+ }
+ if ($8 != NULL) {
+ for (l = $8; l != NULL; l = l->next) {
+ vala_class_add_type_parameter (current_class, l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($8);
+ }
+ if ($9 != NULL) {
+ for (l = $9; l != NULL; l = l->next) {
+ vala_class_add_base_type (current_class, l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($9);
+ }
+ }
+ class_body
+ {
+ $$ = current_class;
+ current_class = NULL;
+ }
+ ;
+
+opt_access_modifier
+ : /* empty */
+ {
+ $$ = 0;
+ }
+ | access_modifier
+ ;
+
+access_modifier
+ : PUBLIC
+ {
+ $$ = VALA_MEMBER_ACCESSIBILITY_PUBLIC;
+ }
+ | PROTECTED
+ {
+ $$ = VALA_MEMBER_ACCESSIBILITY_PROTECTED;
+ }
+ | PRIVATE
+ {
+ $$ = VALA_MEMBER_ACCESSIBILITY_PRIVATE;
+ }
+ ;
+
+opt_modifiers
+ : /* empty */
+ {
+ $$ = VALA_MODIFIER_NONE;
+ }
+ | modifiers
+ ;
+
+modifiers
+ : modifier
+ | modifiers modifier
+ {
+ if (($1 & $2) == $2) {
+ /* modifier specified twice, signal error */
+ }
+ $$ = $1 | $2;
+ }
+ ;
+
+modifier
+ : ABSTRACT
+ {
+ $$ = VALA_MODIFIER_ABSTRACT;
+ }
+ | OVERRIDE
+ {
+ $$ = VALA_MODIFIER_OVERRIDE;
+ }
+ | STATIC
+ {
+ $$ = VALA_MODIFIER_STATIC;
+ }
+ | VIRTUAL
+ {
+ $$ = VALA_MODIFIER_VIRTUAL;
+ }
+ ;
+
+opt_class_base
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | class_base
+ ;
+
+class_base
+ : COLON type_list
+ {
+ $$ = $2;
+ }
+ ;
+
+type_list
+ : type_name
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | type_list COMMA type_name
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+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
+ : constant_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_class_add_constant (current_class, $1);
+ g_object_unref ($1);
+ }
+ }
+ | field_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_class_add_field (current_class, $1);
+ g_object_unref ($1);
+ }
+ }
+ | method_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_class_add_method (current_class, $1);
+ g_object_unref ($1);
+ }
+ }
+ | property_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_class_add_property (current_class, $1, FALSE);
+ g_object_unref ($1);
+ }
+ }
+ | signal_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_class_add_signal (current_class, $1);
+ g_object_unref ($1);
+ }
+ }
+ | constructor_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_class_set_constructor (current_class, $1);
+ g_object_unref ($1);
+ }
+ }
+ | destructor_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_class_set_destructor (current_class, $1);
+ g_object_unref ($1);
+ }
+ }
+ ;
+
+constant_declaration
+ : comment opt_attributes opt_access_modifier CONST type variable_declarator SEMICOLON
+ {
+ ValaSourceReference *src = src_com(@5, $1);
+ $$ = vala_constant_new (vala_variable_declarator_get_name ($6), $5, vala_variable_declarator_get_initializer ($6), src);
+ g_object_unref (src);
+ g_object_unref ($5);
+ g_object_unref ($6);
+ if ($3 != 0) {
+ $$->access = $3;
+ }
+ }
+ ;
+
+field_declaration
+ : comment opt_attributes opt_access_modifier opt_modifiers type variable_declarator SEMICOLON
+ {
+ if (!vala_type_reference_get_is_weak ($5)) {
+ vala_type_reference_set_takes_ownership ($5, TRUE);
+ }
+ vala_type_reference_set_is_ref ($5, FALSE);
+
+ ValaSourceReference *src = src_com(@5, $1);
+ $$ = vala_field_new (vala_variable_declarator_get_name ($6), $5, vala_variable_declarator_get_initializer ($6), src);
+ g_object_unref (src);
+ if ($3 != 0) {
+ $$->access = $3;
+ }
+ if (($4 & VALA_MODIFIER_STATIC) == VALA_MODIFIER_STATIC) {
+ vala_field_set_instance ($$, FALSE);
+ }
+ VALA_CODE_NODE($$)->attributes = $2;
+ g_object_unref ($5);
+ g_object_unref ($6);
+ }
+ ;
+
+comment
+ :
+ {
+ $$ = vala_parser_pop_comment (parser);
+ }
+ ;
+
+variable_declarators
+ : variable_declarator
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | variable_declarators COMMA variable_declarator
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+variable_declarator
+ : identifier
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = vala_variable_declarator_new ($1, NULL, src);
+ g_object_unref (src);
+ g_free ($1);
+ }
+ | identifier ASSIGN variable_initializer
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = vala_variable_declarator_new ($1, $3, src);
+ g_object_unref (src);
+ g_free ($1);
+ g_object_unref ($3);
+ }
+ ;
+
+initializer
+ : OPEN_BRACE opt_variable_initializer_list CLOSE_BRACE
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_initializer_list_new (src));
+ g_object_unref (src);
+
+ if ($2 != NULL) {
+ GList *l;
+ for (l = $2; l != NULL; l = l->next) {
+ vala_initializer_list_append (VALA_INITIALIZER_LIST ($$), l->data);
+ g_object_unref (l->data);
+ }
+ }
+ }
+ ;
+
+opt_variable_initializer_list
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | variable_initializer_list
+ ;
+
+variable_initializer_list
+ : variable_initializer
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | variable_initializer_list COMMA variable_initializer
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+variable_initializer
+ : expression
+ | initializer
+ ;
+
+method_declaration
+ : method_header method_body
+ {
+ $$ = $1;
+ vala_method_set_body ($$, VALA_BLOCK($2));
+ if ($2 != NULL) {
+ g_object_unref ($2);
+ }
+ }
+ | error method_body
+ {
+ $$ = NULL;
+ }
+ ;
+
+method_header
+ : comment opt_attributes opt_access_modifier opt_modifiers type identifier OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS opt_throws_declaration
+ {
+ GList *l;
+
+ if (!vala_type_reference_get_is_weak ($5)) {
+ vala_type_reference_set_transfers_ownership ($5, TRUE);
+ }
+
+ ValaSourceReference *src = src_com(@6, $1);
+ $$ = vala_method_new ($6, $5, src);
+ g_object_unref (src);
+ if ($3 != 0) {
+ $$->access = $3;
+ }
+ if (($4 & VALA_MODIFIER_STATIC) == VALA_MODIFIER_STATIC) {
+ vala_method_set_instance ($$, FALSE);
+ }
+ if (($4 & VALA_MODIFIER_ABSTRACT) == VALA_MODIFIER_ABSTRACT) {
+ vala_method_set_is_abstract ($$, TRUE);
+ }
+ if (($4 & VALA_MODIFIER_VIRTUAL) == VALA_MODIFIER_VIRTUAL) {
+ vala_method_set_is_virtual ($$, TRUE);
+ }
+ if (($4 & VALA_MODIFIER_OVERRIDE) == VALA_MODIFIER_OVERRIDE) {
+ vala_method_set_overrides ($$, TRUE);
+ }
+ VALA_CODE_NODE($$)->attributes = $2;
+
+ for (l = $8; l != NULL; l = l->next) {
+ vala_method_add_parameter ($$, l->data);
+ g_object_unref (l->data);
+ }
+ if ($8 != NULL) {
+ g_list_free ($8);
+ }
+
+ g_object_unref ($5);
+ g_free ($6);
+ }
+ | comment opt_attributes opt_access_modifier opt_modifiers identifier opt_name_specifier OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
+ {
+ GList *l;
+
+ ValaSourceReference *src = src_com(@5, $1);
+ $$ = VALA_METHOD (vala_creation_method_new ($6, src));
+ g_free ($5);
+ g_free ($6);
+ g_object_unref (src);
+ vala_method_set_instance ($$, FALSE);
+ if ($3 != 0) {
+ $$->access = $3;
+ }
+ VALA_CODE_NODE($$)->attributes = $2;
+
+ if ($8 != NULL) {
+ for (l = $8; l != NULL; l = l->next) {
+ vala_method_add_parameter ($$, l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($8);
+ }
+ }
+ ;
+
+method_body
+ : block
+ | SEMICOLON
+ {
+ $$ = NULL;
+ }
+ ;
+
+opt_formal_parameter_list
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | formal_parameter_list
+ ;
+
+formal_parameter_list
+ : fixed_parameters
+ | fixed_parameters COMMA ELLIPSIS
+ {
+ ValaSourceReference *src = src(@3);
+ $$ = g_list_append ($1, vala_formal_parameter_new_with_ellipsis (src));
+ g_object_unref (src);
+ }
+ | ELLIPSIS
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = g_list_append (NULL, vala_formal_parameter_new_with_ellipsis (src));
+ g_object_unref (src);
+ }
+ ;
+
+fixed_parameters
+ : fixed_parameter
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | fixed_parameters COMMA fixed_parameter
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+opt_construct
+ : /* empty */
+ {
+ $$ = FALSE;
+ }
+ | CONSTRUCT
+ {
+ $$ = TRUE;
+ }
+ ;
+
+fixed_parameter
+ : opt_attributes opt_construct type identifier
+ {
+ if (vala_type_reference_get_is_ref ($3) && vala_type_reference_get_is_out ($3)) {
+ vala_type_reference_set_takes_ownership ($3, TRUE);
+ vala_type_reference_set_is_ref ($3, FALSE);
+ }
+
+ ValaSourceReference *src = src(@3);
+ $$ = vala_formal_parameter_new ($4, $3, src);
+ g_object_unref (src);
+ vala_formal_parameter_set_construct_parameter ($$, $2);
+ g_object_unref ($3);
+ g_free ($4);
+ }
+ | opt_attributes opt_construct type identifier ASSIGN expression
+ {
+ if (vala_type_reference_get_is_ref ($3) && vala_type_reference_get_is_out ($3)) {
+ vala_type_reference_set_takes_ownership ($3, TRUE);
+ vala_type_reference_set_is_ref ($3, FALSE);
+ }
+
+ ValaSourceReference *src = src(@3);
+ $$ = vala_formal_parameter_new ($4, $3, src);
+ g_object_unref (src);
+ vala_formal_parameter_set_default_expression ($$, $6);
+ vala_formal_parameter_set_construct_parameter ($$, $2);
+ g_object_unref ($3);
+ g_free ($4);
+ g_object_unref ($6);
+ }
+ ;
+
+opt_throws_declaration
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | throws_declaration
+ ;
+
+throws_declaration
+ : THROWS type_list
+ {
+ $$ = $2;
+ }
+ ;
+
+property_declaration
+ : comment opt_attributes opt_access_modifier opt_modifiers type identifier OPEN_BRACE get_accessor_declaration opt_set_accessor_declaration CLOSE_BRACE
+ {
+ if (!vala_type_reference_get_is_weak ($5)) {
+ vala_type_reference_set_takes_ownership ($5, TRUE);
+ }
+
+ ValaSourceReference *src = src_com(@5, $1);
+ $$ = vala_property_new ($6, $5, $8, $9, src);
+ g_object_unref (src);
+
+ VALA_CODE_NODE($$)->attributes = $2;
+
+ g_object_unref ($5);
+ g_free ($6);
+ g_object_unref ($8);
+ if ($9 != NULL) {
+ g_object_unref ($9);
+ }
+
+ if (($4 & VALA_MODIFIER_ABSTRACT) == VALA_MODIFIER_ABSTRACT) {
+ vala_property_set_is_abstract ($$, TRUE);
+ }
+ if (($4 & VALA_MODIFIER_VIRTUAL) == VALA_MODIFIER_VIRTUAL) {
+ vala_property_set_is_virtual ($$, TRUE);
+ }
+ if (($4 & VALA_MODIFIER_OVERRIDE) == VALA_MODIFIER_OVERRIDE) {
+ vala_property_set_overrides ($$, TRUE);
+ }
+ }
+ | comment opt_attributes opt_access_modifier opt_modifiers type identifier OPEN_BRACE set_accessor_declaration CLOSE_BRACE
+ {
+ if (!vala_type_reference_get_is_weak ($5)) {
+ vala_type_reference_set_takes_ownership ($5, TRUE);
+ }
+
+ ValaSourceReference *src = src_com(@5, $1);
+ $$ = vala_property_new ($6, $5, NULL, $8, src);
+ g_object_unref (src);
+
+ VALA_CODE_NODE($$)->attributes = $2;
+
+ g_object_unref ($5);
+ g_free ($6);
+ g_object_unref ($8);
+
+ if (($4 & VALA_MODIFIER_ABSTRACT) == VALA_MODIFIER_ABSTRACT) {
+ vala_property_set_is_abstract ($$, TRUE);
+ }
+ if (($4 & VALA_MODIFIER_VIRTUAL) == VALA_MODIFIER_VIRTUAL) {
+ vala_property_set_is_virtual ($$, TRUE);
+ }
+ if (($4 & VALA_MODIFIER_OVERRIDE) == VALA_MODIFIER_OVERRIDE) {
+ vala_property_set_overrides ($$, TRUE);
+ }
+ }
+ ;
+
+get_accessor_declaration
+ : opt_attributes GET method_body
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = vala_property_accessor_new (TRUE, FALSE, FALSE, $3, src);
+ g_object_unref (src);
+
+ if ($3 != NULL) {
+ g_object_unref ($3);
+ }
+ }
+ ;
+
+opt_set_accessor_declaration
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | set_accessor_declaration
+ ;
+
+set_accessor_declaration
+ : opt_attributes SET method_body
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = vala_property_accessor_new (FALSE, TRUE, FALSE, $3, src);
+ g_object_unref (src);
+ if ($3 != NULL) {
+ g_object_unref ($3);
+ }
+ }
+ | opt_attributes SET CONSTRUCT method_body
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = vala_property_accessor_new (FALSE, TRUE, TRUE, $4, src);
+ g_object_unref (src);
+ if ($4 != NULL) {
+ g_object_unref ($4);
+ }
+ }
+ | opt_attributes CONSTRUCT method_body
+ {
+ ValaSourceReference *src = src(@2);
+ $$ = vala_property_accessor_new (FALSE, FALSE, TRUE, $3, src);
+ g_object_unref (src);
+ if ($3 != NULL) {
+ g_object_unref ($3);
+ }
+ }
+ ;
+
+signal_declaration
+ : comment opt_attributes opt_access_modifier SIGNAL type identifier OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS SEMICOLON
+ {
+ GList *l;
+
+ ValaSourceReference *src = src_com(@6, $1);
+ $$ = vala_signal_new ($6, $5, src);
+ g_object_unref (src);
+ if ($3 != 0) {
+ vala_signal_set_access ($$, $3);
+ }
+ VALA_CODE_NODE($$)->attributes = $2;
+
+ for (l = $8; l != NULL; l = l->next) {
+ vala_signal_add_parameter ($$, l->data);
+ g_object_unref (l->data);
+ }
+ if ($8 != NULL) {
+ g_list_free ($8);
+ }
+
+ g_object_unref ($5);
+ g_free ($6);
+ }
+ ;
+
+constructor_declaration
+ : comment opt_attributes CONSTRUCT block
+ {
+ ValaSourceReference *src = src_com(@3, $1);
+ $$ = vala_constructor_new (src);
+ g_object_unref (src);
+ vala_constructor_set_body ($$, $4);
+ g_object_unref ($4);
+ }
+ ;
+
+destructor_declaration
+ : comment opt_attributes opt_access_modifier opt_modifiers TILDE identifier OPEN_PARENS CLOSE_PARENS block
+ {
+ ValaSourceReference *src = src_com(@6, $1);
+ $$ = vala_destructor_new (src);
+ g_object_unref (src);
+ vala_destructor_set_body ($$, $9);
+
+ g_free ($6);
+ g_object_unref ($9);
+ }
+ ;
+
+struct_declaration
+ : struct_header
+ {
+ current_struct = $1;
+ }
+ struct_body
+ {
+ $$ = current_struct;
+ current_struct = NULL;
+ }
+ ;
+
+struct_header
+ : comment opt_attributes opt_access_modifier STRUCT identifier opt_name_specifier opt_type_parameter_list opt_class_base
+ {
+ char *name = $5;
+
+ if ($6 != NULL) {
+ ValaSourceReference *ns_src = src(@5);
+ current_namespace = vala_namespace_new ($5, ns_src);
+ g_free ($5);
+ g_object_unref (ns_src);
+ current_namespace_implicit = TRUE;
+
+ vala_source_file_add_namespace (current_source_file, current_namespace);
+ g_object_unref (current_namespace);
+
+ name = $6;
+ }
+
+ GList *l;
+ ValaSourceReference *src = src_com(@5, $1);
+ $$ = vala_struct_new (name, src);
+ g_free (name);
+ g_object_unref (src);
+ for (l = $7; l != NULL; l = l->next) {
+ vala_struct_add_type_parameter ($$, l->data);
+ }
+ VALA_CODE_NODE($$)->attributes = $2;
+ if ($3 != 0) {
+ VALA_DATA_TYPE($$)->access = $3;
+ }
+ if ($8 != NULL) {
+ for (l = $8; l != NULL; l = l->next) {
+ vala_struct_add_base_type ($$, l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($8);
+ }
+ }
+ ;
+
+struct_body
+ : OPEN_BRACE opt_struct_member_declarations CLOSE_BRACE
+ ;
+
+opt_struct_member_declarations
+ : /* empty */
+ | struct_member_declarations
+ ;
+
+struct_member_declarations
+ : struct_member_declaration
+ | struct_member_declarations struct_member_declaration
+ ;
+
+struct_member_declaration
+ : field_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_struct_add_field (current_struct, $1);
+ g_object_unref ($1);
+ }
+ }
+ | method_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_struct_add_method (current_struct, $1);
+ g_object_unref ($1);
+ }
+ }
+ ;
+
+interface_declaration
+ : comment opt_attributes opt_access_modifier opt_modifiers INTERFACE identifier opt_name_specifier opt_type_parameter_list opt_class_base
+ {
+ char *name = $6;
+
+ if ($7 != NULL) {
+ ValaSourceReference *ns_src = src(@6);
+ current_namespace = vala_namespace_new ($6, ns_src);
+ g_free ($6);
+ g_object_unref (ns_src);
+ current_namespace_implicit = TRUE;
+
+ vala_source_file_add_namespace (current_source_file, current_namespace);
+ g_object_unref (current_namespace);
+
+ name = $7;
+ }
+
+ ValaSourceReference *src = src_com(@6, $1);
+ current_interface = vala_interface_new (name, src);
+ g_free (name);
+ g_object_unref (src);
+
+ VALA_CODE_NODE(current_interface)->attributes = $2;
+ if ($3 != 0) {
+ VALA_DATA_TYPE(current_interface)->access = $3;
+ }
+ if (($4 & VALA_MODIFIER_STATIC) == VALA_MODIFIER_STATIC) {
+ vala_interface_set_is_static (current_interface, TRUE);
+ }
+ if ($8 != NULL) {
+ GList *l;
+ for (l = $8; l != NULL; l = l->next) {
+ vala_interface_add_type_parameter (current_interface, l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($8);
+ }
+ if ($9 != NULL) {
+ GList *l;
+ for (l = $9; l != NULL; l = l->next) {
+ vala_interface_add_prerequisite (current_interface, l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($9);
+ }
+ }
+ interface_body
+ {
+ $$ = current_interface;
+ }
+ ;
+
+interface_body
+ : OPEN_BRACE opt_interface_member_declarations CLOSE_BRACE
+ ;
+
+opt_interface_member_declarations
+ : /* empty */
+ | interface_member_declarations
+ ;
+
+interface_member_declarations
+ : interface_member_declaration
+ | interface_member_declarations interface_member_declaration
+ ;
+
+interface_member_declaration
+ : method_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_interface_add_method (current_interface, $1);
+ g_object_unref ($1);
+ }
+ }
+ | property_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_interface_add_property (current_interface, $1);
+ g_object_unref ($1);
+ }
+ }
+ | signal_declaration
+ {
+ /* skip declarations with errors */
+ if ($1 != NULL) {
+ vala_interface_add_signal (current_interface, $1);
+ g_object_unref ($1);
+ }
+ }
+ ;
+
+enum_declaration
+ : comment opt_attributes opt_access_modifier ENUM identifier opt_name_specifier enum_body
+ {
+ char *name = $5;
+
+ if ($6 != NULL) {
+ ValaSourceReference *ns_src = src(@5);
+ current_namespace = vala_namespace_new ($5, ns_src);
+ g_free ($5);
+ g_object_unref (ns_src);
+ current_namespace_implicit = TRUE;
+
+ vala_source_file_add_namespace (current_source_file, current_namespace);
+ g_object_unref (current_namespace);
+
+ name = $6;
+ }
+
+ GList *l;
+ ValaSourceReference *src = src_com(@5, $1);
+ $$ = vala_enum_new (name, src);
+ g_free (name);
+ g_object_unref (src);
+
+ VALA_CODE_NODE($$)->attributes = $2;
+
+ if ($3 != 0) {
+ VALA_DATA_TYPE($$)->access = $3;
+ }
+ for (l = $7; l != NULL; l = l->next) {
+ vala_enum_add_value ($$, l->data);
+ g_object_unref (l->data);
+ }
+ }
+ ;
+
+enum_body
+ : OPEN_BRACE opt_enum_member_declarations CLOSE_BRACE
+ {
+ $$ = $2;
+ }
+ ;
+
+opt_enum_member_declarations
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | enum_member_declarations opt_comma
+ ;
+
+enum_member_declarations
+ : enum_member_declaration
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | enum_member_declarations COMMA enum_member_declaration
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+enum_member_declaration
+ : opt_attributes identifier
+ {
+ $$ = vala_enum_value_new ($2);
+ g_free ($2);
+ }
+ | opt_attributes identifier ASSIGN expression
+ {
+ $$ = vala_enum_value_new_with_value ($2, $4);
+ g_free ($2);
+ g_object_unref ($4);
+ }
+ ;
+
+flags_declaration
+ : comment opt_attributes opt_access_modifier FLAGS identifier opt_name_specifier flags_body
+ {
+ char *name = $5;
+
+ if ($6 != NULL) {
+ ValaSourceReference *ns_src = src(@5);
+ current_namespace = vala_namespace_new ($5, ns_src);
+ g_free ($5);
+ g_object_unref (ns_src);
+ current_namespace_implicit = TRUE;
+
+ vala_source_file_add_namespace (current_source_file, current_namespace);
+ g_object_unref (current_namespace);
+
+ name = $6;
+ }
+
+ GList *l;
+ ValaSourceReference *src = src_com(@5, $1);
+ $$ = vala_flags_new (name, src);
+ g_free (name);
+ g_object_unref (src);
+
+ VALA_CODE_NODE($$)->attributes = $2;
+
+ if ($3 != 0) {
+ VALA_DATA_TYPE($$)->access = $3;
+ }
+ for (l = $7; l != NULL; l = l->next) {
+ vala_flags_add_value ($$, l->data);
+ g_object_unref (l->data);
+ }
+ }
+ ;
+
+flags_body
+ : OPEN_BRACE opt_flags_member_declarations CLOSE_BRACE
+ {
+ $$ = $2;
+ }
+ ;
+
+opt_flags_member_declarations
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | flags_member_declarations opt_comma
+ ;
+
+flags_member_declarations
+ : flags_member_declaration
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | flags_member_declarations COMMA flags_member_declaration
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+flags_member_declaration
+ : opt_attributes identifier
+ {
+ $$ = vala_flags_value_new ($2);
+ g_free ($2);
+ }
+ | opt_attributes identifier ASSIGN expression
+ {
+ $$ = vala_flags_value_new_with_value ($2, $4);
+ g_free ($2);
+ g_object_unref ($4);
+ }
+ ;
+
+callback_declaration
+ : comment opt_attributes opt_access_modifier CALLBACK type identifier opt_name_specifier opt_type_parameter_list OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS SEMICOLON
+ {
+ GList *l;
+ char *name = $6;
+
+ if ($7 != NULL) {
+ ValaSourceReference *ns_src = src(@6);
+ current_namespace = vala_namespace_new ($6, ns_src);
+ g_free ($6);
+ g_object_unref (ns_src);
+ current_namespace_implicit = TRUE;
+
+ vala_source_file_add_namespace (current_source_file, current_namespace);
+ g_object_unref (current_namespace);
+
+ name = $7;
+ }
+
+ ValaSourceReference *src = src_com(@6, $1);
+ $$ = vala_callback_new (name, $5, src);
+ g_free (name);
+ g_object_unref ($5);
+ g_object_unref (src);
+ if ($3 != 0) {
+ VALA_DATA_TYPE($$)->access = $3;
+ }
+ VALA_CODE_NODE($$)->attributes = $2;
+
+ if ($8 != NULL) {
+ for (l = $8; l != NULL; l = l->next) {
+ vala_callback_add_type_parameter ($$, l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($8);
+ }
+ if ($10 != NULL) {
+ for (l = $10; l != NULL; l = l->next) {
+ vala_callback_add_parameter ($$, l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($10);
+ }
+ }
+ ;
+
+opt_attributes
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | attributes
+ ;
+
+attributes
+ : attribute_sections
+ ;
+
+attribute_sections
+ : attribute_section
+ | attribute_sections attribute_section
+ {
+ $$ = g_list_concat ($1, $2);
+ }
+ ;
+
+attribute_section
+ : OPEN_BRACKET attribute_list CLOSE_BRACKET
+ {
+ $$ = $2;
+ }
+ | OPEN_BRACKET error CLOSE_BRACKET
+ {
+ $$ = NULL;
+ }
+ ;
+
+attribute_list
+ : attribute
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | attribute_list COMMA attribute
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+attribute
+ : attribute_name
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = vala_attribute_new ($1, src);
+ g_free ($1);
+ g_object_unref (src);
+ }
+ | attribute_name OPEN_PARENS opt_named_argument_list CLOSE_PARENS
+ {
+ GList *l;
+
+ ValaSourceReference *src = src(@1);
+ $$ = vala_attribute_new ($1, src);
+ g_object_unref (src);
+
+ for (l = $3; l != NULL; l = l->next) {
+ vala_attribute_add_argument ($$, l->data);
+ g_object_unref (l->data);
+ }
+ if ($3 != NULL) {
+ g_list_free ($3);
+ }
+
+ g_free ($1);
+ }
+ ;
+
+attribute_name
+ : identifier
+ ;
+
+opt_named_argument_list
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | named_argument_list
+ ;
+
+named_argument_list
+ : named_argument
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | named_argument_list COMMA named_argument
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+named_argument
+ : identifier ASSIGN expression
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = vala_named_argument_new ($1, $3, src);
+ g_object_unref (src);
+
+ g_free ($1);
+ g_object_unref ($3);
+ }
+ ;
+
+opt_type_parameter_list
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | type_parameter_list
+ ;
+
+type_parameter_list
+ : GENERIC_LT type_parameters OP_GT
+ {
+ $$ = $2;
+ }
+ ;
+
+type_parameters
+ : type_parameter
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | type_parameters COMMA type_parameter
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+type_parameter
+ : identifier
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = vala_type_parameter_new ($1, src);
+ g_object_unref (src);
+ g_free ($1);
+ }
+ ;
+
+opt_type_argument_list
+ : /* empty */
+ {
+ $$ = NULL;
+ }
+ | type_argument_list
+ ;
+
+type_argument_list
+ : GENERIC_LT type_arguments OP_GT
+ {
+ $$ = $2;
+ }
+ ;
+
+type_arguments
+ : type_argument
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | type_arguments COMMA type_argument
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+type_argument
+ : type
+ {
+ $$ = $1;
+ if (!vala_type_reference_get_is_weak ($$)) {
+ vala_type_reference_set_takes_ownership ($$, TRUE);
+ }
+ }
+ ;
+
+open_parens
+ : OPEN_PARENS
+ | OPEN_CAST_PARENS
+ ;
+
+member_name
+ : identifier opt_type_argument_list
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_member_access_new (NULL, $1, src));
+ g_free ($1);
+ g_object_unref (src);
+
+ if ($2 != NULL) {
+ GList *l;
+ for (l = $2; l != NULL; l = l->next) {
+ vala_member_access_add_type_argument (VALA_MEMBER_ACCESS ($$), l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($2);
+ }
+ }
+ | member_name DOT identifier opt_type_argument_list
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_member_access_new ($1, $3, src));
+ g_object_unref ($1);
+ g_free ($3);
+ g_object_unref (src);
+
+ if ($4 != NULL) {
+ GList *l;
+ for (l = $4; l != NULL; l = l->next) {
+ vala_member_access_add_type_argument (VALA_MEMBER_ACCESS ($$), l->data);
+ g_object_unref (l->data);
+ }
+ g_list_free ($4);
+ }
+ }
+ ;
+
+%%
+
+extern FILE *yyin;
+extern int yylineno;
+
+static void
+yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg)
+{
+ ValaSourceReference *source_reference = vala_source_reference_new (current_source_file, locp->first_line, locp->first_column, locp->last_line, locp->last_column);
+ vala_report_error (source_reference, (char *) msg);
+}
+
+void
+vala_parser_parse_file (ValaParser *parser, ValaSourceFile *source_file)
+{
+ current_source_file = source_file;
+ current_namespace = vala_source_file_get_global_namespace (source_file);
+ yyin = fopen (vala_source_file_get_filename (current_source_file), "r");
+ if (yyin == NULL) {
+ printf ("Couldn't open source file: %s.\n", vala_source_file_get_filename (current_source_file));
+ return;
+ }
+
+ /* restart line counter on each file */
+ yylineno = 1;
+
+ yyparse (parser);
+ fclose (yyin);
+ yyin = NULL;
+}
diff --git a/vala/scanner.l b/vala/scanner.l
new file mode 100644
index 000000000..c510973da
--- /dev/null
+++ b/vala/scanner.l
@@ -0,0 +1,193 @@
+/* scanner.l
+ *
+ * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
+ *
+ * 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>
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+%{
+#include "vala.h"
+#include "parser.h"
+
+#define YY_DECL int yylex (YYSTYPE *yylval_param, YYLTYPE *yylloc_param, ValaParser *parser)
+
+#define uploc { yylloc->first_column = yylloc->last_column + 1; yylloc->last_column += yyleng; }
+
+static gboolean file_comment = FALSE;
+%}
+
+%option yylineno
+%option bison-bridge
+%option bison-locations
+%option noyywrap
+%option nounput
+
+%x IN_COMMENT
+
+space [ \t\n]*
+ident [[:alnum:]_]+
+decimal_integer_literal (0|[1-9][[:digit:]]*)
+real_literal [[:digit:]]+"."[[:digit:]]*{real_suffix}?
+hex_digit [[:digit:]A-fa-f]
+octal_digit [0-7]
+octal_integer_literal 0{octal_digit}+
+hexadecimal_integer_literal 0x{hex_digit}+
+integer_suffix L|LL|U|UL|ULL
+real_suffix F
+single_character [^\'\\]
+single_string_literal_character [^\"\\]
+simple_escape_sequence \\[\'\"\?\\abfnrtv]
+hexadecimal_escape_sequence \\x{hex_digit}{hex_digit}?{hex_digit}?{hex_digit}?
+character ({single_character}|{simple_escape_sequence})
+string_literal_character ({single_string_literal_character}|{simple_escape_sequence})
+character_literal \'{character}+\'
+string_literal \"{string_literal_character}*\"
+integer_literal ({decimal_integer_literal}|{hexadecimal_integer_literal}|{octal_integer_literal}){integer_suffix}?
+literal ({integer_literal}|{real_literal}|{character_literal}|{string_literal})
+
+%%
+
+"/*" { uploc; file_comment = (yylineno == 1); BEGIN (IN_COMMENT); }
+<IN_COMMENT>"*/" { uploc; BEGIN (INITIAL); yytext[yyleng - 2] = '\0'; vala_parser_push_comment (parser, yytext, file_comment); }
+<IN_COMMENT>[^*\n]+ { uploc; yymore (); }
+<IN_COMMENT>"*" { uploc; yymore (); }
+<IN_COMMENT>\n { yylloc->first_line = yylloc->last_line = yylineno; yylloc->first_column = 1; yylloc->last_column = 0; yymore (); }
+
+"//".* { uploc; vala_parser_push_comment (parser, g_strdup (yytext + 2), FALSE); }
+
+"{" { uploc; return OPEN_BRACE; }
+"}" { uploc; return CLOSE_BRACE; }
+"("({space}"weak")?{space}{ident}("."{ident})?("<"({ident}".")?{ident}(","({ident}".")?{ident})*">")?("["{space}"]")*{space}")"{space}("("|{ident}|{literal}) { yyless (1); uploc; return OPEN_CAST_PARENS; }
+"(" { uploc; return OPEN_PARENS; }
+")" { uploc; return CLOSE_PARENS; }
+"[]" { uploc; return BRACKET_PAIR; }
+"[" { uploc; return OPEN_BRACKET; }
+"]" { uploc; return CLOSE_BRACKET; }
+"..." { uploc; return ELLIPSIS; }
+"." { uploc; return DOT; }
+":" { uploc; return COLON; }
+"," { uploc; return COMMA; }
+";" { uploc; return SEMICOLON; }
+"#" { uploc; return HASH; }
+"?" { uploc; return INTERR; }
+
+"|=" { uploc; return ASSIGN_BITWISE_OR; }
+"&=" { uploc; return ASSIGN_BITWISE_AND; }
+"^=" { uploc; return ASSIGN_BITWISE_XOR; }
+"+=" { uploc; return ASSIGN_ADD; }
+"-=" { uploc; return ASSIGN_SUB; }
+"*=" { uploc; return ASSIGN_MUL; }
+"/=" { uploc; return ASSIGN_DIV; }
+"%=" { uploc; return ASSIGN_PERCENT; }
+"<<=" { uploc; return ASSIGN_SHIFT_LEFT; }
+">>=" { uploc; return ASSIGN_SHIFT_RIGHT; }
+
+"++" { uploc; return OP_INC; }
+"--" { uploc; return OP_DEC; }
+"==" { uploc; return OP_EQ; }
+"!=" { uploc; return OP_NE; }
+"<<" { uploc; return OP_SHIFT_LEFT; }
+">>" { 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; }
+"!" { uploc; return OP_NEG; }
+"||" { uploc; return OP_OR; }
+"|" { uploc; return BITWISE_OR; }
+"&&" { uploc; return OP_AND; }
+"&" { uploc; return BITWISE_AND; }
+"^" { uploc; return CARRET; }
+"~" { uploc; return TILDE; }
+
+"=" { uploc; return ASSIGN; }
+"+" { uploc; return PLUS; }
+"-" { uploc; return MINUS; }
+"*" { uploc; return STAR; }
+"/" { uploc; return DIV; }
+"%" { uploc; return PERCENT; }
+
+"@"[[:alnum:]_]+ { uploc; yylval->str = g_strdup (yytext + 1); return IDENTIFIER; }
+
+"abstract" { uploc; return ABSTRACT; }
+"base" { uploc; return BASE; }
+"break" { uploc; return BREAK; }
+"callback" { uploc; return CALLBACK; }
+"case" { uploc; return CASE; }
+"catch" { uploc; return CATCH; }
+"class" { uploc; return CLASS; }
+"const" { uploc; return CONST; }
+"construct" { uploc; return CONSTRUCT; }
+"continue" { uploc; return CONTINUE; }
+"default" { uploc; return DEFAULT; }
+"do" { uploc; return DO; }
+"else" { uploc; return ELSE; }
+"enum" { uploc; return ENUM; }
+"false" { uploc; return VALA_FALSE; }
+"finally" { uploc; return FINALLY; }
+"flags" { uploc; return FLAGS; }
+"for" { uploc; return FOR; }
+"foreach" { uploc; return FOREACH; }
+"get" { uploc; return GET; }
+"if" { uploc; return IF; }
+"in" { uploc; return IN; }
+"interface" { uploc; return INTERFACE; }
+"is" { uploc; return IS; }
+"lock" { uploc; return LOCK; }
+"namespace" { uploc; return NAMESPACE; }
+"new" { uploc; return NEW; }
+"null" { uploc; return VALA_NULL; }
+"out" { uploc; return OUT; }
+"override" { uploc; return OVERRIDE; }
+"private" { uploc; return PRIVATE; }
+"protected" { uploc; return PROTECTED; }
+"public" { uploc; return PUBLIC; }
+"ref" { uploc; return REF; }
+"set" { uploc; return SET; }
+"signal" { uploc; return SIGNAL; }
+"static" { uploc; return STATIC; }
+"struct" { uploc; return STRUCT; }
+"switch" { uploc; return SWITCH; }
+"return" { uploc; return RETURN; }
+"this" { uploc; return THIS; }
+"throw" { uploc; return THROW; }
+"throws" { uploc; return THROWS; }
+"true" { uploc; return VALA_TRUE; }
+"try" { uploc; return TRY; }
+"typeof" { uploc; return TYPEOF; }
+"using" { uploc; return USING; }
+"var" { uploc; return VAR; }
+"virtual" { uploc; return VIRTUAL; }
+"weak" { uploc; return WEAK; }
+"while" { uploc; return WHILE; }
+
+{real_literal} { uploc; yylval->str = g_strdup (yytext); return REAL_LITERAL; }
+{integer_literal} { uploc; yylval->str = g_strdup (yytext); return INTEGER_LITERAL; }
+
+{character_literal} { uploc; yylval->str = g_strdup (yytext); return CHARACTER_LITERAL; }
+{string_literal} { uploc; yylval->str = g_strdup (yytext); return STRING_LITERAL; }
+
+{ident} { uploc; yylval->str = g_strdup (yytext); return IDENTIFIER; }
+
+[ \t]+ { uploc; /* eat up whitespace */ }
+[\n]+ { yylloc->first_line = yylloc->last_line = yylineno; yylloc->first_column = 1; yylloc->last_column = 0; }
+
+. { uploc; fprintf (stderr, "%d: syntax error: unexpected character ´%s´\n", yylloc->first_line, yytext); }
diff --git a/vala/vala.h b/vala/vala.h
new file mode 100644
index 000000000..9b66faa92
--- /dev/null
+++ b/vala/vala.h
@@ -0,0 +1,78 @@
+#include <vala/valaaddressofexpression.h>
+#include <vala/valaarraycreationexpression.h>
+#include <vala/valaassignment.h>
+#include <vala/valaattribute.h>
+#include <vala/valabaseaccess.h>
+#include <vala/valabinaryexpression.h>
+#include <vala/valablock.h>
+#include <vala/valabooleanliteral.h>
+#include <vala/valabreakstatement.h>
+#include <vala/valacallback.h>
+#include <vala/valacastexpression.h>
+#include <vala/valacatchclause.h>
+#include <vala/valacharacterliteral.h>
+#include <vala/valaclass.h>
+#include <vala/valacodecontext.h>
+#include <vala/valaconditionalexpression.h>
+#include <vala/valaconstant.h>
+#include <vala/valaconstructor.h>
+#include <vala/valacontinuestatement.h>
+#include <vala/valacreationmethod.h>
+#include <vala/valadeclarationstatement.h>
+#include <vala/valadestructor.h>
+#include <vala/valadostatement.h>
+#include <vala/valaelementaccess.h>
+#include <vala/valaemptystatement.h>
+#include <vala/valaenum.h>
+#include <vala/valaenumvalue.h>
+#include <vala/valaexpression.h>
+#include <vala/valaexpressionstatement.h>
+#include <vala/valafield.h>
+#include <vala/valaflags.h>
+#include <vala/valaforeachstatement.h>
+#include <vala/valaformalparameter.h>
+#include <vala/valaforstatement.h>
+#include <vala/valaifstatement.h>
+#include <vala/valainitializerlist.h>
+#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>
+#include <vala/valalockstatement.h>
+#include <vala/valamemberaccess.h>
+#include <vala/valamethod.h>
+#include <vala/valanamedargument.h>
+#include <vala/valanamespace.h>
+#include <vala/valanamespacereference.h>
+#include <vala/valanullliteral.h>
+#include <vala/valaobjectcreationexpression.h>
+#include <vala/valaparenthesizedexpression.h>
+#include <vala/valaparser.h>
+#include <vala/valapointerindirection.h>
+#include <vala/valapostfixexpression.h>
+#include <vala/valaproperty.h>
+#include <vala/valapropertyaccessor.h>
+#include <vala/valarealliteral.h>
+#include <vala/valareferencetransferexpression.h>
+#include <vala/valareport.h>
+#include <vala/valareturnstatement.h>
+#include <vala/valasignal.h>
+#include <vala/valasourcefile.h>
+#include <vala/valasourcereference.h>
+#include <vala/valastringliteral.h>
+#include <vala/valastruct.h>
+#include <vala/valaswitchlabel.h>
+#include <vala/valaswitchsection.h>
+#include <vala/valaswitchstatement.h>
+#include <vala/valathrowstatement.h>
+#include <vala/valatrystatement.h>
+#include <vala/valatypecheck.h>
+#include <vala/valatypeofexpression.h>
+#include <vala/valatypeparameter.h>
+#include <vala/valatypereference.h>
+#include <vala/valaunaryexpression.h>
+#include <vala/valavariabledeclarator.h>
+#include <vala/valawhilestatement.h>
diff --git a/vala/valaaddressofexpression.vala b/vala/valaaddressofexpression.vala
new file mode 100644
index 000000000..8cfb82524
--- /dev/null
+++ b/vala/valaaddressofexpression.vala
@@ -0,0 +1,64 @@
+/* valaaddressofexpression.vala
+ *
+ * Copyright (C) 2007 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;
+
+/**
+ * Represents an address-of expression in the source code, e.g. `&foo'.
+ */
+public class Vala.AddressofExpression : Expression {
+ /**
+ * The variable whose address is to be computed.
+ */
+ public Expression! inner {
+ get {
+ return _inner;
+ }
+ set construct {
+ _inner = value;
+ _inner.parent_node = this;
+ }
+ }
+
+ private Expression! _inner;
+
+ /**
+ * Creates a new address-of expression.
+ *
+ * @param inner variable whose address is to be computed
+ * @return newly created address-of expression
+ */
+ public AddressofExpression (construct Expression! inner, construct SourceReference source_reference = null) {
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ inner.accept (visitor);
+
+ visitor.visit_addressof_expression (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (inner == old_node) {
+ inner = (Expression) new_node;
+ }
+ }
+}
diff --git a/vala/valaarray.vala b/vala/valaarray.vala
new file mode 100644
index 000000000..d1e5fa131
--- /dev/null
+++ b/vala/valaarray.vala
@@ -0,0 +1,201 @@
+/* valaarray.vala
+ *
+ * Copyright (C) 2006-2007 Raffaele Sandrini, 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:
+ * Raffaele Sandrini <rasa@gmx.ch>
+ * Jürg Billeter <j@bitron.ch>
+ */
+
+using GLib;
+
+/**
+ * Represents an array type i.e. everything with direct accessable elements.
+ */
+public class Vala.Array : DataType {
+
+ /**
+ * DataType of which this is an array of.
+ */
+ public DataType element_type { get; set construct; }
+
+ /**
+ * TypeParameter of which this is an array of.
+ */
+ public TypeParameter element_type_parameter { get; set construct; }
+
+ /**
+ * The rank of this array.
+ */
+ public int rank { get; set construct; }
+
+ private string cname;
+
+ private ArrayLengthField length_field;
+
+ private ArrayResizeMethod resize_method;
+
+ public Array (DataType! _element_type, int _rank, SourceReference! _source_reference) {
+ rank = _rank;
+ element_type = _element_type;
+ source_reference = _source_reference;
+ }
+
+ public Array.with_type_parameter (TypeParameter! _element_type_parameter, int _rank, SourceReference! _source_reference) {
+ rank = _rank;
+ element_type_parameter = _element_type_parameter;
+ source_reference = _source_reference;
+ }
+
+ construct {
+ /* FIXME: this implementation reveals compiler bugs
+ string commas = "";
+ int i = rank - 1;
+
+ while (i > 0) {
+ string += ",";
+ i--;
+ }
+
+ name = "%s[%s]".printf (element_type.name, commas); */
+
+ if (rank < 1) {
+ Report.error (null, "internal: attempt to create an array with rank smaller than 1");
+ }
+
+ int i = rank - 1;
+ if (element_type != null) {
+ name = "%s[".printf (element_type.name);
+ } else {
+ name = "%s[".printf (element_type_parameter.name);
+ }
+ while (i > 0) {
+ name = "%s,".printf (name);
+ i--;
+ }
+ name = "%s]".printf (name);
+
+ length_field = new ArrayLengthField (source_reference);
+ length_field.symbol = new Symbol (length_field);
+
+ resize_method = new ArrayResizeMethod (source_reference);
+ resize_method.symbol = new Symbol (resize_method);
+ }
+
+ /**
+ * Returns the name of this data type as it is used in C code.
+ *
+ * @return the name to be used in C code
+ */
+ public override string get_cname (bool const_type = false) {
+ if (cname == null) {
+ if (element_type != null) {
+ if (element_type.is_reference_type ()) {
+ cname = "%s*".printf (element_type.get_cname ());
+ } else {
+ cname = element_type.get_cname ();
+ }
+ } else {
+ cname = "gpointer";
+ }
+ }
+
+ return cname;
+ }
+
+ /**
+ * Checks whether this data type has value or reference type semantics.
+ *
+ * @return true if this data type has reference type semantics
+ */
+ public override bool is_reference_type () {
+ return true;
+ }
+
+ /**
+ * Returns the C name of this data type in upper case. Words are
+ * separated by underscores. The upper case C name of the namespace is
+ * prefix of the result.
+ *
+ * @param infix a string to be placed between namespace and data type
+ * name or null
+ * @return the upper case name to be used in C code
+ */
+ public override ref string get_upper_case_cname (string infix) {
+ return null;
+ }
+
+ /**
+ * Returns the C name of this data type in lower case. Words are
+ * separated by underscores. The lower case C name of the namespace is
+ * prefix of the result.
+ *
+ * @param infix a string to be placed between namespace and data type
+ * name or null
+ * @return the lower case name to be used in C code
+ */
+ public override ref string get_lower_case_cname (string infix) {
+ return null;
+ }
+
+ /**
+ * Returns the C function name that frees instances of this data type.
+ * This is only valid for data types with reference type semantics that
+ * do not support reference counting. The specified C function must
+ * accept one argument pointing to the instance to be freed.
+ *
+ * @return the name of the C function or null if this data type is not a
+ * reference type or if it supports reference counting
+ */
+ public override string get_free_function () {
+ return "g_free";
+ }
+
+ /**
+ * Returns a list of C header filenames users of this data type must
+ * include.
+ *
+ * @return list of C header filenames for this data type
+ */
+ public override ref List<string> get_cheader_filenames () {
+ if (element_type != null) {
+ return element_type.get_cheader_filenames ();
+ } else {
+ return null;
+ }
+ }
+
+ public override string get_marshaller_type_name () {
+ return "POINTER";
+ }
+
+ public override string get_get_value_function () {
+ return "g_value_get_pointer";
+ }
+
+ public override string get_set_value_function () {
+ return "g_value_set_pointer";
+ }
+
+ public ArrayLengthField get_length_field () {
+ return length_field;
+ }
+
+ public ArrayResizeMethod get_resize_method () {
+ return resize_method;
+ }
+}
diff --git a/vala/valaarraycreationexpression.vala b/vala/valaarraycreationexpression.vala
new file mode 100644
index 000000000..376e03f74
--- /dev/null
+++ b/vala/valaarraycreationexpression.vala
@@ -0,0 +1,89 @@
+/* valaarraycreationexpression.vala
+ *
+ * Copyright (C) 2006 Raffaele Sandrini
+ *
+ * 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:
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+using GLib;
+
+/**
+ * Represents an array creation expression e.g. "new int[] {1,2,3}".
+ */
+public class Vala.ArrayCreationExpression : Expression {
+ /**
+ * The type of the elements of the array.
+ */
+ public TypeReference element_type { get; set construct; }
+
+ /**
+ * The rank of the array.
+ */
+ public int rank { get; set construct; }
+
+ /**
+ * The size for each dimension ascending from left to right.
+ */
+ private List<Expression> sizes;
+
+ /**
+ * The root array initializer list.
+ */
+ public InitializerList initializer_list { get; set construct; }
+
+ /**
+ * Add a size expression.
+ */
+ public void append_size (Expression! size) {
+ sizes.append (size);
+ }
+
+ /**
+ * Get the sizes for all dimensions ascending from left to right.
+ */
+ public ref List<weak Expression> get_sizes () {
+ return sizes.copy ();
+ }
+
+ public ArrayCreationExpression (TypeReference _element_type, int _rank, InitializerList _initializer, SourceReference source) {
+ element_type = _element_type;
+ rank = _rank;
+ initializer_list = _initializer;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ if (element_type != null) {
+ element_type.accept (visitor);
+ }
+
+ if (sizes != null) {
+ foreach (Expression e in sizes) {
+ e.accept (visitor);
+ }
+ }
+
+ visitor.visit_begin_array_creation_expression (this);
+
+ if (initializer_list != null) {
+ initializer_list.accept (visitor);
+ }
+
+ visitor.visit_end_array_creation_expression (this);
+ }
+}
diff --git a/vala/valaarraylengthfield.vala b/vala/valaarraylengthfield.vala
new file mode 100644
index 000000000..5e332c760
--- /dev/null
+++ b/vala/valaarraylengthfield.vala
@@ -0,0 +1,46 @@
+/* valaarraylengthfield.vala
+ *
+ * Copyright (C) 2007 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;
+
+/**
+ * Represents the Array.length field.
+ */
+public class Vala.ArrayLengthField : Field {
+ construct {
+ access = MemberAccessibility.PUBLIC;
+
+ var root_symbol = source_reference.file.context.get_root ();
+ type_reference.data_type = (DataType) root_symbol.lookup ("int").node;
+ }
+
+ /**
+ * Creates a new array length field.
+ *
+ * @return newly created field
+ */
+ public ArrayLengthField (SourceReference! source) {
+ name = "length";
+ type_reference = new TypeReference ();
+ source_reference = source;
+ }
+}
diff --git a/vala/valaarrayresizemethod.vala b/vala/valaarrayresizemethod.vala
new file mode 100644
index 000000000..d2a5bf51a
--- /dev/null
+++ b/vala/valaarrayresizemethod.vala
@@ -0,0 +1,53 @@
+/* valaarrayresizemethod.vala
+ *
+ * Copyright (C) 2007 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;
+
+/**
+ * Represents the Array.resize method.
+ */
+public class Vala.ArrayResizeMethod : Method {
+ construct {
+ access = MemberAccessibility.PUBLIC;
+
+ set_cname ("g_renew");
+
+ var root_symbol = source_reference.file.context.get_root ();
+ var int_type = new TypeReference ();
+ int_type.data_type = (DataType) root_symbol.lookup ("int").node;
+
+ add_parameter (new FormalParameter ("length", int_type));
+
+ returns_modified_pointer = true;
+ }
+
+ /**
+ * Creates a new array resize method.
+ *
+ * @return newly created method
+ */
+ public ArrayResizeMethod (SourceReference! _source_reference) {
+ name = "resize";
+ return_type = new TypeReference ();
+ source_reference = _source_reference;
+ }
+}
diff --git a/vala/valaassignment.vala b/vala/valaassignment.vala
new file mode 100644
index 000000000..09076a23d
--- /dev/null
+++ b/vala/valaassignment.vala
@@ -0,0 +1,113 @@
+/* valaassignment.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;
+
+/**
+ * Represents an assignment expression in the source code.
+ *
+ * Supports =, |=, &=, ^=, +=, -=, *=, /=, %=, <<=, >>=.
+ */
+public class Vala.Assignment : Expression {
+ /**
+ * Left hand side of the assignment.
+ */
+ public Expression! left {
+ get {
+ return _left;
+ }
+ set construct {
+ _left = value;
+ _left.parent_node = this;
+ }
+ }
+
+ /**
+ * Assignment operator.
+ */
+ public AssignmentOperator operator { get; set; }
+
+ /**
+ * Right hand side of the assignment.
+ */
+ public Expression! right {
+ get {
+ return _right;
+ }
+ set construct {
+ _right = value;
+ _right.parent_node = this;
+ }
+ }
+
+ private Expression! _left;
+ private Expression! _right;
+
+ /**
+ * Creates a new assignment.
+ *
+ * @param left left hand side
+ * @param op assignment operator
+ * @param right right hand side
+ * @param source reference to source code
+ * @return newly created assignment
+ */
+ public Assignment (Expression! _left, Expression! _right, AssignmentOperator _op = AssignmentOperator.SIMPLE, SourceReference _source = null) {
+ left = _left;
+ operator = _op;
+ right = _right;
+ source_reference = _source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ left.accept (visitor);
+
+ visitor.visit_begin_assignment (this);
+
+ right.accept (visitor);
+
+ visitor.visit_end_assignment (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (left == old_node) {
+ left = (Expression) new_node;
+ }
+ if (right == old_node) {
+ right = (Expression) new_node;
+ }
+ }
+}
+
+public enum Vala.AssignmentOperator {
+ SIMPLE,
+ BITWISE_OR,
+ BITWISE_AND,
+ BITWISE_XOR,
+ ADD,
+ SUB,
+ MUL,
+ DIV,
+ PERCENT,
+ SHIFT_LEFT,
+ SHIFT_RIGHT
+}
diff --git a/vala/valaattribute.vala b/vala/valaattribute.vala
new file mode 100644
index 000000000..2978afd8e
--- /dev/null
+++ b/vala/valaattribute.vala
@@ -0,0 +1,142 @@
+/* valaattribute.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;
+
+/**
+ * Represents an attribute specified in the source code.
+ */
+public class Vala.Attribute : CodeNode {
+ /**
+ * The name of the attribute type.
+ */
+ public string! name { get; set construct; }
+
+ /**
+ * Contains all specified attribute arguments.
+ */
+ public List<NamedArgument> args;
+
+ /**
+ * Creates a new attribute.
+ *
+ * @param name attribute type name
+ * @param source reference to source code
+ * @return newly created attribute
+ */
+ public Attribute (string! _name, SourceReference source) {
+ name = _name;
+ source_reference = source;
+ }
+
+ /**
+ * Adds an attribute argument.
+ *
+ * @param arg named argument
+ */
+ public void add_argument (NamedArgument! arg) {
+ args.append (arg);
+ }
+
+ /**
+ * Returns whether this attribute has the specified named argument.
+ *
+ * @param name argument name
+ * @return true if the argument has been found, false otherwise
+ */
+ public bool has_argument (string! name) {
+ // FIXME: use hash table
+ foreach (NamedArgument arg in args) {
+ if (arg.name == name) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the string value of the specified named argument.
+ *
+ * @param name argument name
+ * @return string value
+ */
+ public ref string get_string (string! name) {
+ // FIXME: use hash table
+ foreach (NamedArgument arg in args) {
+ if (arg.name == name) {
+ if (arg.argument is LiteralExpression) {
+ var lit = ((LiteralExpression) arg.argument).literal;
+ if (lit is StringLiteral) {
+ return ((StringLiteral) lit).eval ();
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the integer value of the specified named argument.
+ *
+ * @param name argument name
+ * @return integer value
+ */
+ public int get_integer (string! name) {
+ // FIXME: use hash table
+ foreach (NamedArgument arg in args) {
+ if (arg.name == name) {
+ if (arg.argument is LiteralExpression) {
+ var lit = ((LiteralExpression) arg.argument).literal;
+ if (lit is IntegerLiteral) {
+ return ((IntegerLiteral) lit).value.to_int ();
+ }
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ /**
+ * Returns the boolean value of the specified named argument.
+ *
+ * @param name argument name
+ * @return boolean value
+ */
+ public bool get_bool (string! name) {
+ // FIXME: use hash table
+ foreach (NamedArgument arg in args) {
+ if (arg.name == name) {
+ if (arg.argument is LiteralExpression) {
+ var lit = ((LiteralExpression) arg.argument).literal;
+ if (lit is BooleanLiteral) {
+ return ((BooleanLiteral) lit).value;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/vala/valaattributeprocessor.vala b/vala/valaattributeprocessor.vala
new file mode 100644
index 000000000..2c4901f8f
--- /dev/null
+++ b/vala/valaattributeprocessor.vala
@@ -0,0 +1,86 @@
+/* valaattributeprocessor.vala
+ *
+ * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
+ *
+ * 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>
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+using GLib;
+
+/**
+ * Code visitor processing attributes associated with code nodes.
+ */
+public class Vala.AttributeProcessor : CodeVisitor {
+ /**
+ * Process all attributes found in specified code context.
+ *
+ * @param context a code context
+ */
+ public void process (CodeContext! context) {
+ context.accept (this);
+ }
+
+ public override void visit_begin_namespace (Namespace! ns) {
+ ns.process_attributes ();
+ }
+
+ public override void visit_begin_class (Class! cl) {
+ cl.process_attributes ();
+ }
+
+ public override void visit_begin_struct (Struct! st) {
+ st.process_attributes ();
+ }
+
+ public override void visit_begin_interface (Interface! iface) {
+ iface.process_attributes ();
+ }
+
+ public override void visit_begin_enum (Enum! en) {
+ en.process_attributes ();
+ }
+
+ public override void visit_begin_flags (Flags! fl) {
+ fl.process_attributes ();
+ }
+
+ public override void visit_begin_method (Method! m) {
+ m.process_attributes ();
+ }
+
+ public override void visit_begin_creation_method (CreationMethod! m) {
+ m.process_attributes ();
+ }
+
+ public override void visit_begin_property (Property! prop) {
+ prop.process_attributes ();
+ }
+
+ public override void visit_begin_callback (Callback! cb) {
+ cb.process_attributes ();
+ }
+
+ public override void visit_field (Field! f) {
+ f.process_attributes ();
+ }
+
+ public override void visit_begin_signal (Signal! sig) {
+ sig.process_attributes ();
+ }
+}
diff --git a/vala/valabaseaccess.vala b/vala/valabaseaccess.vala
new file mode 100644
index 000000000..3530e8952
--- /dev/null
+++ b/vala/valabaseaccess.vala
@@ -0,0 +1,46 @@
+/* valabaseaccess.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;
+
+/**
+ * Represents an access to base class members in the source code.
+ */
+public class Vala.BaseAccess : Expression {
+ /**
+ * Creates a new base access expression.
+ *
+ * @param source reference to source code
+ * @return newly created base access expression
+ */
+ public BaseAccess (SourceReference source = null) {
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_base_access (this);
+ }
+
+ public override ref string! to_string () {
+ return "base";
+ }
+}
diff --git a/vala/valabinaryexpression.vala b/vala/valabinaryexpression.vala
new file mode 100644
index 000000000..e7853c944
--- /dev/null
+++ b/vala/valabinaryexpression.vala
@@ -0,0 +1,117 @@
+/* valabinaryexpression.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;
+
+/**
+ * Represents an expression with two operands in the source code.
+ *
+ * Supports +, -, *, /, %, <<, >>, <, >, <=, >=, ==, !=, &, |, ^, &&, ||.
+ */
+public class Vala.BinaryExpression : Expression {
+ /**
+ * The binary operator.
+ */
+ public BinaryOperator operator { get; set; }
+
+ /**
+ * The left operand.
+ */
+ public Expression! left {
+ get {
+ return _left;
+ }
+ set construct {
+ _left = value;
+ _left.parent_node = this;
+ }
+ }
+
+ /**
+ * The right operand.
+ */
+ public Expression! right {
+ get {
+ return _right;
+ }
+ set construct {
+ _right = value;
+ _right.parent_node = this;
+ }
+ }
+
+ private Expression! _left;
+ private Expression! _right;
+
+ /**
+ * Creates a new binary expression.
+ *
+ * @param op binary operator
+ * @param left left operand
+ * @param right right operand
+ * @param source reference to source code
+ * @return newly created binary expression
+ */
+ public BinaryExpression (BinaryOperator op, Expression! _left, Expression! _right, SourceReference source = null) {
+ operator = op;
+ left = _left;
+ right = _right;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ left.accept (visitor);
+ right.accept (visitor);
+
+ visitor.visit_binary_expression (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (left == old_node) {
+ left = (Expression) new_node;
+ }
+ if (right == old_node) {
+ right = (Expression) new_node;
+ }
+ }
+}
+
+public enum Vala.BinaryOperator {
+ PLUS,
+ MINUS,
+ MUL,
+ DIV,
+ MOD,
+ SHIFT_LEFT,
+ SHIFT_RIGHT,
+ LESS_THAN,
+ GREATER_THAN,
+ LESS_THAN_OR_EQUAL,
+ GREATER_THAN_OR_EQUAL,
+ EQUALITY,
+ INEQUALITY,
+ BITWISE_AND,
+ BITWISE_OR,
+ BITWISE_XOR,
+ AND,
+ OR
+}
diff --git a/vala/valablock.vala b/vala/valablock.vala
new file mode 100644
index 000000000..f25da4bdb
--- /dev/null
+++ b/vala/valablock.vala
@@ -0,0 +1,92 @@
+/* valablock.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;
+
+/**
+ * Represents a source code block.
+ */
+public class Vala.Block : Statement {
+ /**
+ * Specifies whether this block contains a jump statement. This
+ * information can be used to remove unreachable block cleanup code.
+ */
+ public bool contains_jump_statement { get; set; }
+
+ private List<Statement> statement_list;
+ private List<VariableDeclarator> local_variables;
+
+ /**
+ * Creates a new block.
+ *
+ * @param source reference to source code
+ */
+ public Block (SourceReference source = null) {
+ source_reference = source;
+ }
+
+ /**
+ * Append a statement to this block.
+ *
+ * @param stmt a statement
+ */
+ public void add_statement (Statement! stmt) {
+ statement_list.append (stmt);
+ }
+
+ /**
+ * Returns a copy of the list of statements.
+ *
+ * @return statement list
+ */
+ public ref List<weak Statement> get_statements () {
+ return statement_list.copy ();
+ }
+
+ /**
+ * Add a local variable to this block.
+ *
+ * @param decl a variable declarator
+ */
+ public void add_local_variable (VariableDeclarator! decl) {
+ local_variables.append (decl);
+ }
+
+ /**
+ * Returns a copy of the list of local variables.
+ *
+ * @return variable declarator list
+ */
+ public ref List<weak VariableDeclarator> get_local_variables () {
+ return local_variables.copy ();
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_block (this);
+
+ foreach (Statement! stmt in statement_list) {
+ stmt.accept (visitor);
+ }
+
+ visitor.visit_end_block (this);
+ }
+}
diff --git a/vala/valabooleanliteral.vala b/vala/valabooleanliteral.vala
new file mode 100644
index 000000000..9d10994b7
--- /dev/null
+++ b/vala/valabooleanliteral.vala
@@ -0,0 +1,57 @@
+/* valabooleanliteral.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;
+
+/**
+ * Represents a literal boolean, i.e. true or false.
+ */
+public class Vala.BooleanLiteral : Literal {
+ /**
+ * The literal value.
+ */
+ public bool value { get; set; }
+
+ /**
+ * Creates a new boolean literal.
+ *
+ * @param b boolean value
+ * @param source reference to source code
+ * @return newly created boolean literal
+ */
+ public BooleanLiteral (bool b, SourceReference source) {
+ value = b;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_boolean_literal (this);
+ }
+
+ public override ref string! to_string () {
+ if (value) {
+ return "true";
+ } else {
+ return "false";
+ }
+ }
+}
diff --git a/vala/valabreakstatement.vala b/vala/valabreakstatement.vala
new file mode 100644
index 000000000..25f91b837
--- /dev/null
+++ b/vala/valabreakstatement.vala
@@ -0,0 +1,42 @@
+/* valabreakstatement.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;
+
+/**
+ * Represents a break statement in the source code.
+ */
+public class Vala.BreakStatement : Statement {
+ /**
+ * Creates a new break statement.
+ *
+ * @param source reference to source code
+ * @return newly created break statement
+ */
+ public BreakStatement (SourceReference source) {
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_break_statement (this);
+ }
+}
diff --git a/vala/valacallback.vala b/vala/valacallback.vala
new file mode 100644
index 000000000..c563622f0
--- /dev/null
+++ b/vala/valacallback.vala
@@ -0,0 +1,202 @@
+/* valacallback.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * Represents a function callback type.
+ */
+public class Vala.Callback : DataType {
+ /**
+ * The return type of this callback.
+ */
+ public TypeReference return_type { get; set; }
+
+ /**
+ * Specifies whether callback supports calling instance methods.
+ * The reference to the object instance will be appended to the end of
+ * the argument list in the generated C code.
+ */
+ public bool instance { get; set; }
+
+ private List<TypeParameter> type_parameters;
+
+ private List<FormalParameter> parameters;
+ private string cname;
+
+ /**
+ * Creates a new callback.
+ *
+ * @param name callback type name
+ * @param return_type return type
+ * @param source reference to source code
+ * @return newly created callback
+ */
+ public Callback (string _name, TypeReference _return_type, SourceReference source = null) {
+ name = _name;
+ return_type = _return_type;
+ source_reference = source;
+ }
+
+ /**
+ * Appends the specified parameter to the list of type parameters.
+ *
+ * @param p a type parameter
+ */
+ public void add_type_parameter (TypeParameter! p) {
+ type_parameters.append (p);
+ p.type = this;
+ }
+
+ /**
+ * Appends paramater to this callback function.
+ *
+ * @param param a formal parameter
+ */
+ public void add_parameter (FormalParameter! param) {
+ parameters.append (param);
+ }
+
+ /**
+ * Return copy of parameter list.
+ *
+ * @return parameter list
+ */
+ public ref List<weak FormalParameter> get_parameters () {
+ return parameters.copy ();
+ }
+
+ /**
+ * Checks whether the arguments and return type of the specified method
+ * matches this callback.
+ *
+ * @param m a method
+ * @return true if the specified method is compatible to this callback
+ */
+ public bool matches_method (Method! m) {
+ if (!m.return_type.stricter (return_type)) {
+ return false;
+ }
+
+ var method_params = m.get_parameters ();
+ weak List<weak FormalParameter> method_params_it = method_params;
+ bool first = true;
+ foreach (FormalParameter param in parameters) {
+ /* use first callback parameter as instance parameter if
+ * an instance method is being compared to a static
+ * callback
+ */
+ if (first && m.instance && !instance) {
+ first = false;
+ continue;
+ }
+
+ /* method is allowed to accept less arguments */
+ if (method_params_it == null) {
+ break;
+ }
+
+ var method_param = (FormalParameter) method_params_it.data;
+ if (!param.type_reference.stricter (method_param.type_reference)) {
+ return false;
+ }
+
+ method_params_it = method_params_it.next;
+ }
+
+ /* method may not expect more arguments */
+ if (method_params_it != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_callback (this);
+
+ foreach (TypeParameter p in type_parameters) {
+ p.accept (visitor);
+ }
+
+ return_type.accept (visitor);
+
+ foreach (FormalParameter! param in parameters) {
+ param.accept (visitor);
+ }
+
+ visitor.visit_end_callback (this);
+ }
+
+ public override string get_cname (bool const_type = false) {
+ if (cname == null) {
+ cname = "%s%s".printf (@namespace.get_cprefix (), name);
+ }
+ return cname;
+ }
+
+ /**
+ * Sets the name of this callback as it is used in C code.
+ *
+ * @param cname the name to be used in C code
+ */
+ public void set_cname (string cname) {
+ this.cname = cname;
+ }
+
+ private void process_ccode_attribute (Attribute a) {
+ if (a.has_argument ("cname")) {
+ set_cname (a.get_string ("cname"));
+ }
+ }
+
+ /**
+ * Process all associated attributes.
+ */
+ public void process_attributes () {
+ foreach (Attribute a in attributes) {
+ if (a.name == "CCode") {
+ process_ccode_attribute (a);
+ }
+ }
+ }
+
+ public override bool is_reference_type () {
+ return false;
+ }
+
+ public override string get_type_id () {
+ return "G_TYPE_POINTER";
+ }
+
+ public override string get_marshaller_type_name () {
+ return "POINTER";
+ }
+
+ public override string get_get_value_function () {
+ return "g_value_get_pointer";
+ }
+
+ public override string get_set_value_function () {
+ return "g_value_set_pointer";
+ }
+}
diff --git a/vala/valacastexpression.vala b/vala/valacastexpression.vala
new file mode 100644
index 000000000..8900ed9b6
--- /dev/null
+++ b/vala/valacastexpression.vala
@@ -0,0 +1,74 @@
+/* valacastexpression.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;
+
+/**
+ * Represents a type cast in the source code.
+ */
+public class Vala.CastExpression : Expression {
+ /**
+ * The expression to be cast.
+ */
+ public Expression! inner {
+ get {
+ return _inner;
+ }
+ set construct {
+ _inner = value;
+ _inner.parent_node = this;
+ }
+ }
+
+ /**
+ * The target type.
+ */
+ public TypeReference! type_reference { get; set construct; }
+
+ private Expression! _inner;
+
+ /**
+ * Creates a new cast expression.
+ *
+ * @param inner expression to be cast
+ * @param type target type
+ * @return newly created cast expression
+ */
+ public CastExpression (Expression! _inner, TypeReference! type, SourceReference source) {
+ inner = _inner;
+ type_reference = type;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ inner.accept (visitor);
+ type_reference.accept (visitor);
+
+ visitor.visit_cast_expression (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (inner == old_node) {
+ inner = (Expression) new_node;
+ }
+ }
+}
diff --git a/vala/valacatchclause.vala b/vala/valacatchclause.vala
new file mode 100644
index 000000000..3c8af19e7
--- /dev/null
+++ b/vala/valacatchclause.vala
@@ -0,0 +1,69 @@
+/* valacatchclause.vala
+ *
+ * Copyright (C) 2007 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;
+
+/**
+ * Represents a catch clause in a try statement in the source code.
+ */
+public class Vala.CatchClause : CodeNode {
+ /**
+ * Specifies the error type.
+ */
+ public TypeReference type_reference { get; set; }
+
+ /**
+ * Specifies the error variable name.
+ */
+ public string variable_name { get; set; }
+
+ /**
+ * Specifies the error handler body.
+ */
+ public Block body { get; set; }
+
+ /**
+ * Specifies the declarator for the generated error variable.
+ */
+ public VariableDeclarator variable_declarator { get; set; }
+
+ /**
+ * Creates a new catch clause.
+ *
+ * @param type_reference error type
+ * @param variable_name error variable name
+ * @param body error handler body
+ * @param source_reference reference to source code
+ * @return newly created catch clause
+ */
+ public CatchClause (construct TypeReference type_reference, construct string variable_name, construct Block body, construct SourceReference source_reference = null) {
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_catch_clause (this);
+
+ type_reference.accept (visitor);
+ body.accept (visitor);
+
+ visitor.visit_end_catch_clause (this);
+ }
+}
diff --git a/vala/valacharacterliteral.vala b/vala/valacharacterliteral.vala
new file mode 100644
index 000000000..21605709a
--- /dev/null
+++ b/vala/valacharacterliteral.vala
@@ -0,0 +1,80 @@
+/* valacharacterliteral.vala
+ *
+ * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
+ *
+ * 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>
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+using GLib;
+
+/**
+ * Represents a single literal character.
+ */
+public class Vala.CharacterLiteral : Literal {
+ /**
+ * The literal value.
+ */
+ public string! value {
+ get {
+ return _value;
+ }
+ set construct {
+ _value = value;
+
+ if (!value.validate () || (value.len () != 3 && value.next_char ().get_char () != '\\')) {
+ error = true;
+ }
+ }
+ }
+
+ private string! _value;
+
+ /**
+ * Creates a new character literal.
+ *
+ * @param c character
+ * @param source reference to source code
+ * @return newly created character literal
+ */
+ public CharacterLiteral (string! c, SourceReference source) {
+ value = c;
+ source_reference = source;
+
+ }
+
+ construct {
+ if (error) {
+ Report.error (source_reference, "invalid character literal");
+ }
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_character_literal (this);
+ }
+
+ /**
+ * Returns the unicode character value this character literal
+ * represents.
+ *
+ * @return unicode character value
+ */
+ public unichar get_char () {
+ return value.next_char ().get_char ();
+ }
+}
diff --git a/vala/valaclass.vala b/vala/valaclass.vala
new file mode 100644
index 000000000..3f111eb41
--- /dev/null
+++ b/vala/valaclass.vala
@@ -0,0 +1,398 @@
+/* valaclass.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * Represents a class declaration in the source code.
+ */
+public class Vala.Class : DataType {
+ /**
+ * Specifies the base class.
+ */
+ public Class base_class { get; set; }
+
+ /**
+ * Specifies whether this class is abstract. Abstract classes may not be
+ * instantiated.
+ */
+ public bool is_abstract { get; set; }
+
+ /**
+ * Specifies whether this class is static. Static classes may not be
+ * instantiated and may only contain static members.
+ */
+ public bool is_static { get; set; }
+
+ /**
+ * Specifies whether this class has private fields.
+ */
+ public bool has_private_fields {
+ get {
+ return _has_private_fields;
+ }
+ }
+
+ private string cname;
+ private string lower_case_csuffix;
+ private string type_id;
+
+ private bool _has_private_fields;
+
+ private List<TypeParameter> type_parameters;
+
+ private List<TypeReference> base_types;
+
+ private List<Constant> constants;
+ private List<Field> fields;
+ private List<Method> methods;
+ private List<Property> properties;
+ private List<Signal> signals;
+
+ /**
+ * Specifies the default construction method.
+ */
+ public Method default_construction_method { get; set; }
+
+ /**
+ * Specifies the instance constructor.
+ */
+ public Constructor constructor { get; set; }
+
+ /**
+ * Specifies the instance destructor.
+ */
+ public Destructor destructor { get; set; }
+
+ /**
+ * Creates a new class.
+ *
+ * @param name type name
+ * @param source reference to source code
+ * @return newly created class
+ */
+ public Class (string! _name, SourceReference source = null) {
+ name = _name;
+ source_reference = source;
+ }
+
+ /**
+ * Adds the specified class or interface to the list of base types of
+ * this class.
+ *
+ * @param type a class or interface reference
+ */
+ public void add_base_type (TypeReference! type) {
+ base_types.append (type);
+ }
+
+ /**
+ * Returns a copy of the base type list.
+ *
+ * @return list of base types
+ */
+ public ref List<weak TypeReference> get_base_types () {
+ return base_types.copy ();
+ }
+
+ /**
+ * Appends the specified parameter to the list of type parameters.
+ *
+ * @param p a type parameter
+ */
+ public void add_type_parameter (TypeParameter! p) {
+ type_parameters.append (p);
+ p.type = this;
+ }
+
+ /**
+ * Returns a copy of the type parameter list.
+ *
+ * @return list of type parameters
+ */
+ public List<weak TypeParameter> get_type_parameters () {
+ return type_parameters.copy ();
+ }
+
+ /**
+ * Adds the specified constant as a member to this class.
+ *
+ * @param c a constant
+ */
+ public void add_constant (Constant! c) {
+ constants.append (c);
+ }
+
+ /**
+ * Adds the specified field as a member to this class.
+ *
+ * @param f a field
+ */
+ public void add_field (Field! f) {
+ // non_null fields not yet supported due to initialization issues
+ f.type_reference.non_null = false;
+ fields.append (f);
+ if (f.access == MemberAccessibility.PRIVATE && f.instance) {
+ _has_private_fields = true;
+ }
+ }
+
+ /**
+ * Returns a copy of the list of fields.
+ *
+ * @return list of fields
+ */
+ public ref List<weak Field> get_fields () {
+ return fields.copy ();
+ }
+
+ /**
+ * Adds the specified method as a member to this class.
+ *
+ * @param m a method
+ */
+ public void add_method (Method! m) {
+ methods.append (m);
+ }
+
+ /**
+ * Returns a copy of the list of methods.
+ *
+ * @return list of methods
+ */
+ public ref List<weak Method> get_methods () {
+ return methods.copy ();
+ }
+
+ /**
+ * Adds the specified property as a member to this class.
+ *
+ * @param prop a property
+ */
+ public void add_property (Property! prop, bool no_field = false) {
+ properties.append (prop);
+
+ if (!no_field && prop.set_accessor != null && prop.set_accessor.body == null &&
+ source_reference != null && !source_reference.file.pkg) {
+ /* automatic property accessor body generation */
+ var field_type = prop.type_reference.copy ();
+ // non_null fields not yet supported due to initialization issues
+ field_type.non_null = false;
+ var f = new Field ("_%s".printf (prop.name), field_type, null, prop.source_reference);
+ f.access = MemberAccessibility.PRIVATE;
+ add_field (f);
+ }
+ }
+
+ /**
+ * Returns a copy of the list of properties.
+ *
+ * @return list of properties
+ */
+ public ref List<weak Property> get_properties () {
+ return properties.copy ();
+ }
+
+ /**
+ * Adds the specified signal as a member to this class.
+ *
+ * @param sig a signal
+ */
+ public void add_signal (Signal! sig) {
+ signals.append (sig);
+ }
+
+ /**
+ * Returns a copy of the list of signals.
+ *
+ * @return list of signals
+ */
+ public ref List<weak Signal> get_signals () {
+ return signals.copy ();
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_class (this);
+
+ foreach (TypeReference type in base_types) {
+ type.accept (visitor);
+ }
+
+ foreach (TypeParameter p in type_parameters) {
+ p.accept (visitor);
+ }
+
+ foreach (Field f in fields) {
+ f.accept (visitor);
+ }
+
+ foreach (Constant c in constants) {
+ c.accept (visitor);
+ }
+
+ foreach (Method m in methods) {
+ m.accept (visitor);
+ }
+
+ foreach (Property prop in properties) {
+ prop.accept (visitor);
+ }
+
+ foreach (Signal sig in signals) {
+ sig.accept (visitor);
+ }
+
+ if (constructor != null) {
+ constructor.accept (visitor);
+ }
+
+ if (destructor != null) {
+ destructor.accept (visitor);
+ }
+
+ visitor.visit_end_class (this);
+ }
+
+ public override string get_cname (bool const_type = false) {
+ if (cname == null) {
+ cname = "%s%s".printf (@namespace.get_cprefix (), name);
+ }
+ return cname;
+ }
+
+ /**
+ * Sets the name of this class as it is used in C code.
+ *
+ * @param cname the name to be used in C code
+ */
+ public void set_cname (string! cname) {
+ this.cname = cname;
+ }
+
+ private string get_lower_case_csuffix () {
+ if (lower_case_csuffix == null) {
+ lower_case_csuffix = Namespace.camel_case_to_lower_case (name);
+ }
+ return lower_case_csuffix;
+ }
+
+ private void set_lower_case_csuffix (string! csuffix) {
+ this.lower_case_csuffix = csuffix;
+ }
+
+ public override ref string get_lower_case_cname (string infix) {
+ if (infix == null) {
+ infix = "";
+ }
+ return "%s%s%s".printf (@namespace.get_lower_case_cprefix (), infix, get_lower_case_csuffix ());
+ }
+
+ public override ref string get_lower_case_cprefix () {
+ return "%s_".printf (get_lower_case_cname (null));
+ }
+
+ public override ref string get_upper_case_cname (string infix) {
+ return get_lower_case_cname (infix).up ();
+ }
+
+ public override bool is_reference_type () {
+ return true;
+ }
+
+ private void process_ccode_attribute (Attribute! a) {
+ if (a.has_argument ("cname")) {
+ set_cname (a.get_string ("cname"));
+ }
+ if (a.has_argument ("cheader_filename")) {
+ var val = a.get_string ("cheader_filename");
+ foreach (string filename in val.split (",")) {
+ add_cheader_filename (filename);
+ }
+ }
+ }
+
+ /**
+ * Process all associated attributes.
+ */
+ public void process_attributes () {
+ foreach (Attribute a in attributes) {
+ if (a.name == "CCode") {
+ process_ccode_attribute (a);
+ }
+ }
+ }
+
+ public override string get_type_id () {
+ if (type_id == null) {
+ type_id = get_upper_case_cname ("TYPE_");
+ }
+
+ return type_id;
+ }
+
+ public override string get_marshaller_type_name () {
+ return "OBJECT";
+ }
+
+ public override string get_get_value_function () {
+ return "g_value_get_object";
+ }
+
+ public override string get_set_value_function () {
+ return "g_value_set_object";
+ }
+
+ public override bool is_reference_counting () {
+ return true;
+ }
+
+ public override string get_ref_function () {
+ return "g_object_ref";
+ }
+
+ public override string get_unref_function () {
+ return "g_object_unref";
+ }
+
+ public override bool is_subtype_of (DataType! t) {
+ foreach (TypeReference base_type in base_types) {
+ if (base_type.data_type == t ||
+ base_type.data_type.is_subtype_of (t)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public override int get_type_parameter_index (string! name) {
+ int i = 0;
+ foreach (TypeParameter parameter in type_parameters) {
+ if (parameter.name == name) {
+ return i;
+ }
+ i++;
+ }
+ return -1;
+ }
+}
+
diff --git a/vala/valaclassregisterfunction.vala b/vala/valaclassregisterfunction.vala
new file mode 100644
index 000000000..607a04994
--- /dev/null
+++ b/vala/valaclassregisterfunction.vala
@@ -0,0 +1,105 @@
+/* valaclassregisterfunction.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * C function to register a class at runtime.
+ */
+public class Vala.ClassRegisterFunction : TypeRegisterFunction {
+ /**
+ * Specifies the class to be registered.
+ */
+ public Class! class_reference { get; set construct; }
+
+ /**
+ * Creates a new C function to register the specified class at runtime.
+ *
+ * @param cl a class
+ * @return newly created class register function
+ */
+ public ClassRegisterFunction (Class! cl) {
+ class_reference = cl;
+ }
+
+ public override DataType! get_type_declaration () {
+ return class_reference;
+ }
+
+ public override ref string! get_type_struct_name () {
+ return "%sClass".printf (class_reference.get_cname ());
+ }
+
+ public override ref string! get_base_init_func_name () {
+ return "NULL";
+ }
+
+ public override ref string! get_class_init_func_name () {
+ return "%s_class_init".printf (class_reference.get_lower_case_cname (null));
+ }
+
+ public override ref string! get_instance_struct_size () {
+ return "sizeof (%s)".printf (class_reference.get_cname ());
+ }
+
+ public override ref string! get_instance_init_func_name () {
+ return "%s_init".printf (class_reference.get_lower_case_cname (null));
+ }
+
+ public override ref string! get_parent_type_name () {
+ return class_reference.base_class.get_upper_case_cname ("TYPE_");
+ }
+
+ public override string get_type_flags () {
+ if (class_reference.is_abstract) {
+ return "G_TYPE_FLAG_ABSTRACT";
+ } else {
+ return "0";
+ }
+ }
+
+ public override ref CCodeFragment! get_type_interface_init_statements () {
+ var frag = new CCodeFragment ();
+
+ foreach (TypeReference base_type in class_reference.get_base_types ()) {
+ if (!(base_type.data_type is Interface)) {
+ continue;
+ }
+
+ var iface = (Interface) base_type.data_type;
+
+ var iface_info_name = "%s_info".printf (iface.get_lower_case_cname (null));
+
+ var ctypedecl = new CCodeDeclaration ("const GInterfaceInfo");
+ ctypedecl.modifiers = CCodeModifiers.STATIC;
+ ctypedecl.add_declarator (new CCodeVariableDeclarator.with_initializer (iface_info_name, new CCodeConstant ("{ (GInterfaceInitFunc) %s_%s_interface_init, (GInterfaceFinalizeFunc) NULL, NULL}".printf (class_reference.get_lower_case_cname (null), iface.get_lower_case_cname (null)))));
+ frag.append (ctypedecl);
+ var reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_add_interface_static"));
+ reg_call.add_argument (new CCodeIdentifier ("%s_type_id".printf (class_reference.get_lower_case_cname (null))));
+ reg_call.add_argument (new CCodeIdentifier (iface.get_upper_case_cname ("TYPE_")));
+ reg_call.add_argument (new CCodeIdentifier ("&%s".printf (iface_info_name)));
+ frag.append (new CCodeExpressionStatement (reg_call));
+ }
+
+ return frag;
+ }
+}
diff --git a/vala/valacodecontext.vala b/vala/valacodecontext.vala
new file mode 100644
index 000000000..40d64d85b
--- /dev/null
+++ b/vala/valacodecontext.vala
@@ -0,0 +1,237 @@
+/* valacodecontext.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * The root of the code tree.
+ */
+public class Vala.CodeContext {
+ /**
+ * Specifies the name of the library to be built.
+ *
+ * Public header files of a library will be assumed to be installed in
+ * a subdirectory named like the library.
+ */
+ public string library { get; set; }
+
+ /**
+ * Specifies the optional module initialization method.
+ */
+ public Method module_init_method { get; set; }
+
+ List<SourceFile> source_files;
+ private Symbol! root = new Symbol ();
+
+ List<SourceFileCycle> cycles;
+
+ /**
+ * Returns the root symbol of the code tree.
+ *
+ * @return root symbol
+ */
+ public Symbol! get_root () {
+ return root;
+ }
+
+ /**
+ * Returns a copy of the list of source files.
+ *
+ * @return list of source files
+ */
+ public ref List<weak SourceFile> get_source_files () {
+ return source_files.copy ();
+ }
+
+ /**
+ * Adds the specified file to the list of source files.
+ *
+ * @param file a source file
+ */
+ public void add_source_file (SourceFile! file) {
+ source_files.append (file);
+ }
+
+ /**
+ * Visits the complete code tree file by file.
+ *
+ * @param visitor the visitor to be called when traversing
+ */
+ public void accept (CodeVisitor! visitor) {
+ foreach (SourceFile file in source_files) {
+ file.accept (visitor);
+ }
+ }
+
+ /**
+ * Find and resolve cycles in source file dependencies.
+ */
+ public void find_header_cycles () {
+ /* find cycles in dependencies between source files */
+ foreach (SourceFile file in source_files) {
+ /* we're only interested in internal source files */
+ if (file.pkg) {
+ continue;
+ }
+
+ if (file.mark == 0) {
+ visit (file, null);
+ }
+ }
+
+ /* find one head for each cycle, it must not have any
+ * hard dependencies on other files in the cycle
+ */
+ foreach (SourceFileCycle cycle in cycles) {
+ cycle.head = find_cycle_head ((SourceFile) cycle.files.data);
+ cycle.head.is_cycle_head = true;
+ }
+
+ /* connect the source files in a non-cyclic way
+ * cycle members connect to the head of their cycle
+ */
+ foreach (SourceFile file2 in source_files) {
+ /* we're only interested in internal source files */
+ if (file2.pkg) {
+ continue;
+ }
+
+ foreach (SourceFile dep in file2.get_header_internal_dependencies ()) {
+ if (file2.cycle != null && dep.cycle == file2.cycle) {
+ /* in the same cycle */
+ if (!file2.is_cycle_head) {
+ /* include header of cycle head */
+ file2.add_header_internal_include (file2.cycle.head.get_cinclude_filename ());
+ }
+ } else {
+ /* we can just include the headers if they are not in a cycle or not in the same cycle as the current file */
+ file2.add_header_internal_include (dep.get_cinclude_filename ());
+ }
+ }
+ }
+
+ }
+
+ private weak SourceFile find_cycle_head (SourceFile! file) {
+ foreach (SourceFile dep in file.get_header_internal_full_dependencies ()) {
+ if (dep == file) {
+ /* ignore file-internal dependencies */
+ continue;
+ }
+
+ foreach (SourceFile cycle_file in file.cycle.files) {
+ if (dep == cycle_file) {
+ return find_cycle_head (dep);
+ }
+ }
+ }
+ /* no hard dependencies on members of the same cycle found
+ * source file suitable as cycle head
+ */
+ return file;
+ }
+
+ private void visit (SourceFile! file, List<SourceFile> chain) {
+ /* no deep copy available yet
+ * var l = chain.copy ();
+ */
+ ref List<weak SourceFile> l = null;
+ foreach (SourceFile chain_file in chain) {
+ l.append (chain_file);
+ }
+ l.append (file);
+ /* end workaround */
+
+ /* mark file as currently being visited */
+ file.mark = 1;
+
+ foreach (SourceFile dep in file.get_header_internal_dependencies ()) {
+ if (file == dep) {
+ continue;
+ }
+
+ if (dep.mark == 1) {
+ /* found cycle */
+
+ var cycle = new SourceFileCycle ();
+ cycles.append (cycle);
+
+ bool cycle_start_found = false;
+ foreach (SourceFile cycle_file in l) {
+ ref SourceFileCycle ref_cycle_file_cycle = cycle_file.cycle;
+ if (!cycle_start_found) {
+ if (cycle_file == dep) {
+ cycle_start_found = true;
+ }
+ }
+
+ if (!cycle_start_found) {
+ continue;
+ }
+
+ if (cycle_file.cycle != null) {
+ /* file already in a cycle */
+
+ if (cycle_file.cycle == cycle) {
+ /* file is in the same cycle, nothing to do */
+ continue;
+ }
+
+ /* file is in an other cycle, merge the two cycles */
+
+ /* broken memory management cycles.remove (cycle_file.cycle); */
+ ref List<weak SourceFileCycle> newlist = null;
+ foreach (SourceFileCycle oldcycle in cycles) {
+ if (oldcycle != cycle_file.cycle) {
+ newlist.append (oldcycle);
+ }
+ }
+ cycles = null;
+ foreach (SourceFileCycle newcycle in newlist) {
+ cycles.append (newcycle);
+ }
+ newlist = null;
+ /* end workaround for broken memory management */
+
+ foreach (SourceFile inner_cycle_file in cycle_file.cycle.files) {
+ if (inner_cycle_file.cycle != cycle) {
+ /* file in inner cycle not yet added to outer cycle */
+ cycle.files.append (inner_cycle_file);
+ inner_cycle_file.cycle = cycle;
+ }
+ }
+ } else {
+ cycle.files.append (cycle_file);
+ cycle_file.cycle = cycle;
+ }
+ }
+ } else if (dep.mark == 0) {
+ /* found not yet visited file */
+
+ visit (dep, l);
+ }
+ }
+
+ /* mark file as successfully visited */
+ file.mark = 2;
+ }
+}
diff --git a/vala/valacodegenerator.vala b/vala/valacodegenerator.vala
new file mode 100644
index 000000000..8a8807142
--- /dev/null
+++ b/vala/valacodegenerator.vala
@@ -0,0 +1,4177 @@
+/* valacodegenerator.vala
+ *
+ * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
+ *
+ * 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>
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+using GLib;
+
+/**
+ * Code visitor generating C Code.
+ */
+public class Vala.CodeGenerator : CodeVisitor {
+ /**
+ * Specifies whether automatic memory management is active.
+ */
+ public bool memory_management { get; set; }
+
+ private CodeContext context;
+
+ Symbol root_symbol;
+ Symbol current_symbol;
+ Symbol current_type_symbol;
+ Class current_class;
+ TypeReference current_return_type;
+
+ CCodeFragment header_begin;
+ CCodeFragment header_type_declaration;
+ CCodeFragment header_type_definition;
+ CCodeFragment header_type_member_declaration;
+ CCodeFragment source_begin;
+ CCodeFragment source_include_directives;
+ CCodeFragment source_type_member_declaration;
+ CCodeFragment source_signal_marshaller_declaration;
+ CCodeFragment source_type_member_definition;
+ CCodeFragment instance_init_fragment;
+ CCodeFragment instance_dispose_fragment;
+ CCodeFragment source_signal_marshaller_definition;
+ CCodeFragment module_init_fragment;
+
+ CCodeStruct instance_struct;
+ CCodeStruct type_struct;
+ CCodeStruct instance_priv_struct;
+ CCodeEnum prop_enum;
+ CCodeEnum cenum;
+ CCodeFunction function;
+ CCodeBlock block;
+
+ /* all temporary variables */
+ List<VariableDeclarator> temp_vars;
+ /* temporary variables that own their content */
+ List<VariableDeclarator> temp_ref_vars;
+ /* cache to check whether a certain marshaller has been created yet */
+ HashTable<string,bool> user_marshal_list;
+ /* (constant) hash table with all predefined marshallers */
+ HashTable<string,bool> predefined_marshal_list;
+
+ private int next_temp_var_id = 0;
+ private bool in_creation_method = false;
+
+ TypeReference bool_type;
+ TypeReference char_type;
+ TypeReference unichar_type;
+ TypeReference short_type;
+ TypeReference ushort_type;
+ TypeReference int_type;
+ TypeReference uint_type;
+ TypeReference long_type;
+ TypeReference ulong_type;
+ TypeReference int64_type;
+ TypeReference uint64_type;
+ TypeReference string_type;
+ TypeReference float_type;
+ TypeReference double_type;
+ DataType list_type;
+ DataType slist_type;
+ TypeReference mutex_type;
+ DataType type_module_type;
+
+ private bool in_plugin = false;
+ private string module_init_param_name;
+
+ private bool string_h_needed;
+
+ public CodeGenerator (bool manage_memory = true) {
+ memory_management = manage_memory;
+ }
+
+ construct {
+ predefined_marshal_list = new HashTable (str_hash, str_equal);
+ predefined_marshal_list.insert ("VOID:VOID", true);
+ predefined_marshal_list.insert ("VOID:BOOLEAN", true);
+ predefined_marshal_list.insert ("VOID:CHAR", true);
+ predefined_marshal_list.insert ("VOID:UCHAR", true);
+ predefined_marshal_list.insert ("VOID:INT", true);
+ predefined_marshal_list.insert ("VOID:UINT", true);
+ predefined_marshal_list.insert ("VOID:LONG", true);
+ predefined_marshal_list.insert ("VOID:ULONG", true);
+ predefined_marshal_list.insert ("VOID:ENUM", true);
+ predefined_marshal_list.insert ("VOID:FLAGS", true);
+ predefined_marshal_list.insert ("VOID:FLOAT", true);
+ predefined_marshal_list.insert ("VOID:DOUBLE", true);
+ predefined_marshal_list.insert ("VOID:STRING", true);
+ predefined_marshal_list.insert ("VOID:POINTER", true);
+ predefined_marshal_list.insert ("VOID:OBJECT", true);
+ predefined_marshal_list.insert ("STRING:OBJECT,POINTER", true);
+ predefined_marshal_list.insert ("VOID:UINT,POINTER", true);
+ predefined_marshal_list.insert ("BOOLEAN:FLAGS", true);
+ }
+
+ /**
+ * Generate and emit C code for the specified code context.
+ *
+ * @param context a code context
+ */
+ public void emit (CodeContext! context) {
+ this.context = context;
+
+ context.find_header_cycles ();
+
+ root_symbol = context.get_root ();
+
+ bool_type = new TypeReference ();
+ bool_type.data_type = (DataType) root_symbol.lookup ("bool").node;
+
+ char_type = new TypeReference ();
+ char_type.data_type = (DataType) root_symbol.lookup ("char").node;
+
+ unichar_type = new TypeReference ();
+ unichar_type.data_type = (DataType) root_symbol.lookup ("unichar").node;
+
+ short_type = new TypeReference ();
+ short_type.data_type = (DataType) root_symbol.lookup ("short").node;
+
+ ushort_type = new TypeReference ();
+ ushort_type.data_type = (DataType) root_symbol.lookup ("ushort").node;
+
+ int_type = new TypeReference ();
+ int_type.data_type = (DataType) root_symbol.lookup ("int").node;
+
+ uint_type = new TypeReference ();
+ uint_type.data_type = (DataType) root_symbol.lookup ("uint").node;
+
+ long_type = new TypeReference ();
+ long_type.data_type = (DataType) root_symbol.lookup ("long").node;
+
+ ulong_type = new TypeReference ();
+ ulong_type.data_type = (DataType) root_symbol.lookup ("ulong").node;
+
+ int64_type = new TypeReference ();
+ int64_type.data_type = (DataType) root_symbol.lookup ("int64").node;
+
+ uint64_type = new TypeReference ();
+ uint64_type.data_type = (DataType) root_symbol.lookup ("uint64").node;
+
+ float_type = new TypeReference ();
+ float_type.data_type = (DataType) root_symbol.lookup ("float").node;
+
+ double_type = new TypeReference ();
+ double_type.data_type = (DataType) root_symbol.lookup ("double").node;
+
+ string_type = new TypeReference ();
+ string_type.data_type = (DataType) root_symbol.lookup ("string").node;
+
+ var glib_ns = root_symbol.lookup ("GLib");
+
+ list_type = (DataType) glib_ns.lookup ("List").node;
+ slist_type = (DataType) glib_ns.lookup ("SList").node;
+
+ mutex_type = new TypeReference ();
+ mutex_type.data_type = (DataType) glib_ns.lookup ("Mutex").node;
+
+ type_module_type = (DataType) glib_ns.lookup ("TypeModule").node;
+
+ if (context.module_init_method != null) {
+ module_init_fragment = new CCodeFragment ();
+ foreach (FormalParameter parameter in context.module_init_method.get_parameters ()) {
+ if (parameter.type_reference.data_type == type_module_type) {
+ in_plugin = true;
+ module_init_param_name = parameter.name;
+ break;
+ }
+ }
+ }
+
+ /* we're only interested in non-pkg source files */
+ var source_files = context.get_source_files ();
+ foreach (SourceFile file in source_files) {
+ if (!file.pkg) {
+ file.accept (this);
+ }
+ }
+ }
+
+ private ref CCodeIncludeDirective get_internal_include (string! filename) {
+ return new CCodeIncludeDirective (filename, context.library == null);
+ }
+
+ public override void visit_begin_source_file (SourceFile! source_file) {
+ header_begin = new CCodeFragment ();
+ header_type_declaration = new CCodeFragment ();
+ header_type_definition = new CCodeFragment ();
+ header_type_member_declaration = new CCodeFragment ();
+ source_begin = new CCodeFragment ();
+ source_include_directives = new CCodeFragment ();
+ source_type_member_declaration = new CCodeFragment ();
+ source_type_member_definition = new CCodeFragment ();
+ source_signal_marshaller_definition = new CCodeFragment ();
+ source_signal_marshaller_declaration = new CCodeFragment ();
+
+ user_marshal_list = new HashTable (str_hash, str_equal);
+
+ next_temp_var_id = 0;
+
+ string_h_needed = false;
+
+ header_begin.append (new CCodeIncludeDirective ("glib.h"));
+ header_begin.append (new CCodeIncludeDirective ("glib-object.h"));
+ source_include_directives.append (new CCodeIncludeDirective (source_file.get_cheader_filename (), true));
+
+ ref List<weak string> used_includes = null;
+ used_includes.append ("glib.h");
+ used_includes.append ("glib-object.h");
+ used_includes.append (source_file.get_cheader_filename ());
+
+ foreach (string filename1 in source_file.get_header_external_includes ()) {
+ if (used_includes.find_custom (filename1, strcmp) == null) {
+ header_begin.append (new CCodeIncludeDirective (filename1));
+ used_includes.append (filename1);
+ }
+ }
+ foreach (string filename2 in source_file.get_header_internal_includes ()) {
+ if (used_includes.find_custom (filename2, strcmp) == null) {
+ header_begin.append (get_internal_include (filename2));
+ used_includes.append (filename2);
+ }
+ }
+ foreach (string filename3 in source_file.get_source_external_includes ()) {
+ if (used_includes.find_custom (filename3, strcmp) == null) {
+ source_include_directives.append (new CCodeIncludeDirective (filename3));
+ used_includes.append (filename3);
+ }
+ }
+ foreach (string filename4 in source_file.get_source_internal_includes ()) {
+ if (used_includes.find_custom (filename4, strcmp) == null) {
+ source_include_directives.append (get_internal_include (filename4));
+ used_includes.append (filename4);
+ }
+ }
+ if (source_file.is_cycle_head) {
+ foreach (SourceFile cycle_file in source_file.cycle.files) {
+ var namespaces = cycle_file.get_namespaces ();
+ foreach (Namespace ns in namespaces) {
+ var structs = ns.get_structs ();
+ foreach (Struct st in structs) {
+ header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (st.get_cname ()), new CCodeVariableDeclarator (st.get_cname ())));
+ }
+ var classes = ns.get_classes ();
+ foreach (Class cl in classes) {
+ header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (cl.get_cname ()), new CCodeVariableDeclarator (cl.get_cname ())));
+ header_type_declaration.append (new CCodeTypeDefinition ("struct _%sClass".printf (cl.get_cname ()), new CCodeVariableDeclarator ("%sClass".printf (cl.get_cname ()))));
+ }
+ var ifaces = ns.get_interfaces ();
+ foreach (Interface iface in ifaces) {
+ header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (iface.get_cname ()), new CCodeVariableDeclarator (iface.get_cname ())));
+ header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (iface.get_type_cname ()), new CCodeVariableDeclarator (iface.get_type_cname ())));
+ }
+ }
+ }
+ }
+
+ /* generate hardcoded "well-known" macros */
+ source_begin.append (new CCodeMacroReplacement ("VALA_FREE_CHECKED(o,f)", "((o) == NULL ? NULL : ((o) = (f (o), NULL)))"));
+ source_begin.append (new CCodeMacroReplacement ("VALA_FREE_UNCHECKED(o,f)", "((o) = (f (o), NULL))"));
+ }
+
+ private static ref string get_define_for_filename (string! filename) {
+ var define = new String ("__");
+
+ var i = filename;
+ while (i.len () > 0) {
+ var c = i.get_char ();
+ if (c.isalnum () && c < 0x80) {
+ define.append_unichar (c.toupper ());
+ } else {
+ define.append_c ('_');
+ }
+
+ i = i.next_char ();
+ }
+
+ define.append ("__");
+
+ return define.str;
+ }
+
+ public override void visit_end_source_file (SourceFile! source_file) {
+ var header_define = get_define_for_filename (source_file.get_cheader_filename ());
+
+ if (string_h_needed) {
+ source_include_directives.append (new CCodeIncludeDirective ("string.h"));
+ }
+
+ CCodeComment comment = null;
+ if (source_file.comment != null) {
+ comment = new CCodeComment (source_file.comment);
+ }
+
+ var writer = new CCodeWriter (source_file.get_cheader_filename ());
+ if (comment != null) {
+ comment.write (writer);
+ }
+ writer.write_newline ();
+ var once = new CCodeOnceSection (header_define);
+ once.append (new CCodeNewline ());
+ once.append (header_begin);
+ once.append (new CCodeNewline ());
+ once.append (new CCodeIdentifier ("G_BEGIN_DECLS"));
+ once.append (new CCodeNewline ());
+ once.append (new CCodeNewline ());
+ once.append (header_type_declaration);
+ once.append (new CCodeNewline ());
+ once.append (header_type_definition);
+ once.append (new CCodeNewline ());
+ once.append (header_type_member_declaration);
+ once.append (new CCodeNewline ());
+ once.append (new CCodeIdentifier ("G_END_DECLS"));
+ once.append (new CCodeNewline ());
+ once.append (new CCodeNewline ());
+ once.write (writer);
+ writer.close ();
+
+ writer = new CCodeWriter (source_file.get_csource_filename ());
+ if (comment != null) {
+ comment.write (writer);
+ }
+ source_begin.write (writer);
+ writer.write_newline ();
+ source_include_directives.write (writer);
+ writer.write_newline ();
+ source_type_member_declaration.write (writer);
+ writer.write_newline ();
+ source_signal_marshaller_declaration.write (writer);
+ writer.write_newline ();
+ source_type_member_definition.write (writer);
+ writer.write_newline ();
+ source_signal_marshaller_definition.write (writer);
+ writer.write_newline ();
+ writer.close ();
+
+ header_begin = null;
+ header_type_declaration = null;
+ header_type_definition = null;
+ header_type_member_declaration = null;
+ source_begin = null;
+ source_include_directives = null;
+ source_type_member_declaration = null;
+ source_type_member_definition = null;
+ source_signal_marshaller_definition = null;
+ source_signal_marshaller_declaration = null;
+ }
+
+ public override void visit_begin_class (Class! cl) {
+ current_symbol = cl.symbol;
+ current_type_symbol = cl.symbol;
+ current_class = cl;
+
+ if (cl.is_static) {
+ return;
+ }
+
+ instance_struct = new CCodeStruct ("_%s".printf (cl.get_cname ()));
+ type_struct = new CCodeStruct ("_%sClass".printf (cl.get_cname ()));
+ instance_priv_struct = new CCodeStruct ("_%sPrivate".printf (cl.get_cname ()));
+ prop_enum = new CCodeEnum ();
+ prop_enum.add_value ("%s_DUMMY_PROPERTY".printf (cl.get_upper_case_cname (null)), null);
+ instance_init_fragment = new CCodeFragment ();
+ instance_dispose_fragment = new CCodeFragment ();
+
+
+ header_type_declaration.append (new CCodeNewline ());
+ var macro = "(%s_get_type ())".printf (cl.get_lower_case_cname (null));
+ header_type_declaration.append (new CCodeMacroReplacement (cl.get_upper_case_cname ("TYPE_"), macro));
+
+ macro = "(G_TYPE_CHECK_INSTANCE_CAST ((obj), %s, %s))".printf (cl.get_upper_case_cname ("TYPE_"), cl.get_cname ());
+ header_type_declaration.append (new CCodeMacroReplacement ("%s(obj)".printf (cl.get_upper_case_cname (null)), macro));
+
+ macro = "(G_TYPE_CHECK_CLASS_CAST ((klass), %s, %sClass))".printf (cl.get_upper_case_cname ("TYPE_"), cl.get_cname ());
+ header_type_declaration.append (new CCodeMacroReplacement ("%s_CLASS(klass)".printf (cl.get_upper_case_cname (null)), macro));
+
+ macro = "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), %s))".printf (cl.get_upper_case_cname ("TYPE_"));
+ header_type_declaration.append (new CCodeMacroReplacement ("%s(obj)".printf (cl.get_upper_case_cname ("IS_")), macro));
+
+ macro = "(G_TYPE_CHECK_CLASS_TYPE ((klass), %s))".printf (cl.get_upper_case_cname ("TYPE_"));
+ header_type_declaration.append (new CCodeMacroReplacement ("%s_CLASS(klass)".printf (cl.get_upper_case_cname ("IS_")), macro));
+
+ macro = "(G_TYPE_INSTANCE_GET_CLASS ((obj), %s, %sClass))".printf (cl.get_upper_case_cname ("TYPE_"), cl.get_cname ());
+ header_type_declaration.append (new CCodeMacroReplacement ("%s_GET_CLASS(obj)".printf (cl.get_upper_case_cname (null)), macro));
+ header_type_declaration.append (new CCodeNewline ());
+
+
+ if (cl.source_reference.file.cycle == null) {
+ header_type_declaration.append (new CCodeTypeDefinition ("struct %s".printf (instance_struct.name), new CCodeVariableDeclarator (cl.get_cname ())));
+ header_type_declaration.append (new CCodeTypeDefinition ("struct %s".printf (type_struct.name), new CCodeVariableDeclarator ("%sClass".printf (cl.get_cname ()))));
+ }
+ header_type_declaration.append (new CCodeTypeDefinition ("struct %s".printf (instance_priv_struct.name), new CCodeVariableDeclarator ("%sPrivate".printf (cl.get_cname ()))));
+
+ instance_struct.add_field (cl.base_class.get_cname (), "parent");
+ instance_struct.add_field ("%sPrivate *".printf (cl.get_cname ()), "priv");
+ type_struct.add_field ("%sClass".printf (cl.base_class.get_cname ()), "parent");
+
+ if (cl.source_reference.comment != null) {
+ header_type_definition.append (new CCodeComment (cl.source_reference.comment));
+ }
+ header_type_definition.append (instance_struct);
+ header_type_definition.append (type_struct);
+ source_type_member_declaration.append (instance_priv_struct);
+ macro = "(G_TYPE_INSTANCE_GET_PRIVATE ((o), %s, %sPrivate))".printf (cl.get_upper_case_cname ("TYPE_"), cl.get_cname ());
+ source_type_member_declaration.append (new CCodeMacroReplacement ("%s_GET_PRIVATE(o)".printf (cl.get_upper_case_cname (null)), macro));
+ source_type_member_declaration.append (prop_enum);
+ }
+
+ public override void visit_end_class (Class! cl) {
+ if (!cl.is_static) {
+ add_get_property_function (cl);
+ add_set_property_function (cl);
+ add_class_init_function (cl);
+
+ foreach (TypeReference base_type in cl.get_base_types ()) {
+ if (base_type.data_type is Interface) {
+ add_interface_init_function (cl, (Interface) base_type.data_type);
+ }
+ }
+
+ add_instance_init_function (cl);
+ if (memory_management && cl.get_fields () != null) {
+ add_dispose_function (cl);
+ }
+
+ var type_fun = new ClassRegisterFunction (cl);
+ type_fun.init_from_type (in_plugin);
+ header_type_member_declaration.append (type_fun.get_declaration ());
+ source_type_member_definition.append (type_fun.get_definition ());
+
+ if (in_plugin) {
+ // FIXME resolve potential dependency issues, i.e. base types have to be registered before derived types
+ var register_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_register_type".printf (cl.get_lower_case_cname (null))));
+ register_call.add_argument (new CCodeIdentifier (module_init_param_name));
+ module_init_fragment.append (new CCodeExpressionStatement (register_call));
+ }
+ }
+
+ current_type_symbol = null;
+ current_class = null;
+ instance_dispose_fragment = null;
+ }
+
+ private void add_class_init_function (Class! cl) {
+ var class_init = new CCodeFunction ("%s_class_init".printf (cl.get_lower_case_cname (null)), "void");
+ class_init.add_parameter (new CCodeFormalParameter ("klass", "%sClass *".printf (cl.get_cname ())));
+ class_init.modifiers = CCodeModifiers.STATIC;
+
+ var init_block = new CCodeBlock ();
+ class_init.block = init_block;
+
+ ref CCodeFunctionCall ccall;
+
+ /* save pointer to parent class */
+ var parent_decl = new CCodeDeclaration ("gpointer");
+ var parent_var_decl = new CCodeVariableDeclarator ("%s_parent_class".printf (cl.get_lower_case_cname (null)));
+ parent_var_decl.initializer = new CCodeConstant ("NULL");
+ parent_decl.add_declarator (parent_var_decl);
+ parent_decl.modifiers = CCodeModifiers.STATIC;
+ source_type_member_declaration.append (parent_decl);
+ ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek_parent"));
+ ccall.add_argument (new CCodeIdentifier ("klass"));
+ var parent_assignment = new CCodeAssignment (new CCodeIdentifier ("%s_parent_class".printf (cl.get_lower_case_cname (null))), ccall);
+ init_block.add_statement (new CCodeExpressionStatement (parent_assignment));
+
+ /* add struct for private fields */
+ if (cl.has_private_fields) {
+ ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_add_private"));
+ ccall.add_argument (new CCodeIdentifier ("klass"));
+ ccall.add_argument (new CCodeConstant ("sizeof (%sPrivate)".printf (cl.get_cname ())));
+ init_block.add_statement (new CCodeExpressionStatement (ccall));
+ }
+
+ /* set property handlers */
+ ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
+ ccall.add_argument (new CCodeIdentifier ("klass"));
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccall, "get_property"), new CCodeIdentifier ("%s_get_property".printf (cl.get_lower_case_cname (null))))));
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccall, "set_property"), new CCodeIdentifier ("%s_set_property".printf (cl.get_lower_case_cname (null))))));
+
+ /* set constructor */
+ if (cl.constructor != null) {
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
+ ccast.add_argument (new CCodeIdentifier ("klass"));
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, "constructor"), new CCodeIdentifier ("%s_constructor".printf (cl.get_lower_case_cname (null))))));
+ }
+
+ /* set dispose function */
+ if (memory_management && cl.get_fields () != null) {
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
+ ccast.add_argument (new CCodeIdentifier ("klass"));
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, "dispose"), new CCodeIdentifier ("%s_dispose".printf (cl.get_lower_case_cname (null))))));
+ }
+
+ /* connect overridden methods */
+ var methods = cl.get_methods ();
+ foreach (Method m in methods) {
+ if (m.base_method == null) {
+ continue;
+ }
+ var base_type = m.base_method.symbol.parent_symbol.node;
+
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (((Class) base_type).get_upper_case_cname (null))));
+ ccast.add_argument (new CCodeIdentifier ("klass"));
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, m.name), new CCodeIdentifier (m.get_real_cname ()))));
+ }
+
+ /* create destroy_func properties for generic types */
+ foreach (TypeParameter type_param in cl.get_type_parameters ()) {
+ string func_name = "%s_destroy_func".printf (type_param.name.down ());
+ var func_name_constant = new CCodeConstant ("\"%s-destroy-func\"".printf (type_param.name.down ()));
+ string enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
+ var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
+ cinst.add_argument (ccall);
+ cinst.add_argument (new CCodeConstant (enum_value));
+ var cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
+ cspec.add_argument (func_name_constant);
+ cspec.add_argument (new CCodeConstant ("\"destroy func\""));
+ cspec.add_argument (new CCodeConstant ("\"destroy func\""));
+ cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
+ cinst.add_argument (cspec);
+ init_block.add_statement (new CCodeExpressionStatement (cinst));
+ prop_enum.add_value (enum_value, null);
+
+ instance_priv_struct.add_field ("GDestroyNotify", func_name);
+ }
+
+ /* create properties */
+ var props = cl.get_properties ();
+ foreach (Property prop in props) {
+ if (prop.overrides || prop.base_interface_property != null) {
+ var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_override_property"));
+ cinst.add_argument (ccall);
+ cinst.add_argument (new CCodeConstant (prop.get_upper_case_cname ()));
+ cinst.add_argument (prop.get_canonical_cconstant ());
+
+ init_block.add_statement (new CCodeExpressionStatement (cinst));
+ } else {
+ var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
+ cinst.add_argument (ccall);
+ cinst.add_argument (new CCodeConstant (prop.get_upper_case_cname ()));
+ cinst.add_argument (get_param_spec (prop));
+
+ init_block.add_statement (new CCodeExpressionStatement (cinst));
+ }
+ }
+
+ /* create signals */
+ foreach (Signal sig in cl.get_signals ()) {
+ init_block.add_statement (new CCodeExpressionStatement (get_signal_creation (sig, cl)));
+ }
+
+ source_type_member_definition.append (class_init);
+ }
+
+ private void add_interface_init_function (Class! cl, Interface! iface) {
+ var iface_init = new CCodeFunction ("%s_%s_interface_init".printf (cl.get_lower_case_cname (null), iface.get_lower_case_cname (null)), "void");
+ iface_init.add_parameter (new CCodeFormalParameter ("iface", "%s *".printf (iface.get_type_cname ())));
+ iface_init.modifiers = CCodeModifiers.STATIC;
+
+ var init_block = new CCodeBlock ();
+ iface_init.block = init_block;
+
+ ref CCodeFunctionCall ccall;
+
+ /* save pointer to parent vtable */
+ string parent_iface_var = "%s_%s_parent_iface".printf (cl.get_lower_case_cname (null), iface.get_lower_case_cname (null));
+ var parent_decl = new CCodeDeclaration (iface.get_type_cname () + "*");
+ var parent_var_decl = new CCodeVariableDeclarator (parent_iface_var);
+ parent_var_decl.initializer = new CCodeConstant ("NULL");
+ parent_decl.add_declarator (parent_var_decl);
+ parent_decl.modifiers = CCodeModifiers.STATIC;
+ source_type_member_declaration.append (parent_decl);
+ ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_interface_peek_parent"));
+ ccall.add_argument (new CCodeIdentifier ("iface"));
+ var parent_assignment = new CCodeAssignment (new CCodeIdentifier (parent_iface_var), ccall);
+ init_block.add_statement (new CCodeExpressionStatement (parent_assignment));
+
+ var methods = cl.get_methods ();
+ foreach (Method m in methods) {
+ if (m.base_interface_method == null) {
+ continue;
+ }
+
+ var base_type = m.base_interface_method.symbol.parent_symbol.node;
+ if (base_type != iface) {
+ continue;
+ }
+
+ var ciface = new CCodeIdentifier ("iface");
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ciface, m.name), new CCodeIdentifier (m.get_real_cname ()))));
+ }
+
+ source_type_member_definition.append (iface_init);
+ }
+
+ private void add_instance_init_function (Class! cl) {
+ var instance_init = new CCodeFunction ("%s_init".printf (cl.get_lower_case_cname (null)), "void");
+ instance_init.add_parameter (new CCodeFormalParameter ("self", "%s *".printf (cl.get_cname ())));
+ instance_init.modifiers = CCodeModifiers.STATIC;
+
+ var init_block = new CCodeBlock ();
+ instance_init.block = init_block;
+
+ if (cl.has_private_fields) {
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_PRIVATE".printf (cl.get_upper_case_cname (null))));
+ ccall.add_argument (new CCodeIdentifier ("self"));
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), ccall)));
+ }
+
+ init_block.add_statement (instance_init_fragment);
+
+ var init_sym = cl.symbol.lookup ("init");
+ if (init_sym != null) {
+ var init_fun = (Method) init_sym.node;
+ init_block.add_statement (init_fun.body.ccodenode);
+ }
+
+ source_type_member_definition.append (instance_init);
+ }
+
+ private void add_dispose_function (Class! cl) {
+ function = new CCodeFunction ("%s_dispose".printf (cl.get_lower_case_cname (null)), "void");
+ function.modifiers = CCodeModifiers.STATIC;
+
+ function.add_parameter (new CCodeFormalParameter ("obj", "GObject *"));
+
+ source_type_member_declaration.append (function.copy ());
+
+
+ var cblock = new CCodeBlock ();
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null)));
+ ccall.add_argument (new CCodeIdentifier ("obj"));
+
+ var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
+
+ cblock.add_statement (cdecl);
+
+ cblock.add_statement (instance_dispose_fragment);
+
+ cdecl = new CCodeDeclaration ("%sClass *".printf (cl.get_cname ()));
+ cdecl.add_declarator (new CCodeVariableDeclarator ("klass"));
+ cblock.add_statement (cdecl);
+
+ cdecl = new CCodeDeclaration ("GObjectClass *");
+ cdecl.add_declarator (new CCodeVariableDeclarator ("parent_class"));
+ cblock.add_statement (cdecl);
+
+
+ ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek"));
+ ccall.add_argument (new CCodeIdentifier (cl.get_upper_case_cname ("TYPE_")));
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (cl.get_upper_case_cname (null))));
+ ccast.add_argument (ccall);
+ cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("klass"), ccast)));
+
+ ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek_parent"));
+ ccall.add_argument (new CCodeIdentifier ("klass"));
+ ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
+ ccast.add_argument (ccall);
+ cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("parent_class"), ccast)));
+
+
+ ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("parent_class"), "dispose"));
+ ccall.add_argument (new CCodeIdentifier ("obj"));
+ cblock.add_statement (new CCodeExpressionStatement (ccall));
+
+
+ function.block = cblock;
+
+ source_type_member_definition.append (function);
+ }
+
+ private ref CCodeIdentifier! get_value_setter_function (TypeReference! type_reference) {
+ if (type_reference.data_type is Class || type_reference.data_type is Interface) {
+ return new CCodeIdentifier ("g_value_set_object");
+ } else if (type_reference.data_type == string_type.data_type) {
+ return new CCodeIdentifier ("g_value_set_string");
+ } else if (type_reference.data_type == int_type.data_type
+ || type_reference.data_type is Enum) {
+ return new CCodeIdentifier ("g_value_set_int");
+ } else if (type_reference.data_type == uint_type.data_type) {
+ return new CCodeIdentifier ("g_value_set_uint");
+ } else if (type_reference.data_type == long_type.data_type) {
+ return new CCodeIdentifier ("g_value_set_long");
+ } else if (type_reference.data_type == ulong_type.data_type) {
+ return new CCodeIdentifier ("g_value_set_ulong");
+ } else if (type_reference.data_type == bool_type.data_type) {
+ return new CCodeIdentifier ("g_value_set_boolean");
+ } else if (type_reference.data_type == float_type.data_type) {
+ return new CCodeIdentifier ("g_value_set_float");
+ } else if (type_reference.data_type == double_type.data_type) {
+ return new CCodeIdentifier ("g_value_set_double");
+ } else {
+ return new CCodeIdentifier ("g_value_set_pointer");
+ }
+ }
+
+ private void add_get_property_function (Class! cl) {
+ var get_prop = new CCodeFunction ("%s_get_property".printf (cl.get_lower_case_cname (null)), "void");
+ get_prop.modifiers = CCodeModifiers.STATIC;
+ get_prop.add_parameter (new CCodeFormalParameter ("object", "GObject *"));
+ get_prop.add_parameter (new CCodeFormalParameter ("property_id", "guint"));
+ get_prop.add_parameter (new CCodeFormalParameter ("value", "GValue *"));
+ get_prop.add_parameter (new CCodeFormalParameter ("pspec", "GParamSpec *"));
+
+ var block = new CCodeBlock ();
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null)));
+ ccall.add_argument (new CCodeIdentifier ("object"));
+ var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
+ block.add_statement (cdecl);
+
+ var cswitch = new CCodeSwitchStatement (new CCodeIdentifier ("property_id"));
+ var props = cl.get_properties ();
+ foreach (Property prop in props) {
+ if (prop.get_accessor == null || prop.is_abstract) {
+ continue;
+ }
+
+ bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
+
+ string prefix = cl.get_lower_case_cname (null);
+ if (is_virtual) {
+ prefix += "_real";
+ }
+
+ var ccase = new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ()));
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_get_%s".printf (prefix, prop.name)));
+ ccall.add_argument (new CCodeIdentifier ("self"));
+ var csetcall = new CCodeFunctionCall ();
+ csetcall.call = get_value_setter_function (prop.type_reference);
+ csetcall.add_argument (new CCodeIdentifier ("value"));
+ csetcall.add_argument (ccall);
+ ccase.add_statement (new CCodeExpressionStatement (csetcall));
+ ccase.add_statement (new CCodeBreakStatement ());
+ cswitch.add_case (ccase);
+ }
+ block.add_statement (cswitch);
+
+ get_prop.block = block;
+
+ source_type_member_definition.append (get_prop);
+ }
+
+ private void add_set_property_function (Class! cl) {
+ var set_prop = new CCodeFunction ("%s_set_property".printf (cl.get_lower_case_cname (null)), "void");
+ set_prop.modifiers = CCodeModifiers.STATIC;
+ set_prop.add_parameter (new CCodeFormalParameter ("object", "GObject *"));
+ set_prop.add_parameter (new CCodeFormalParameter ("property_id", "guint"));
+ set_prop.add_parameter (new CCodeFormalParameter ("value", "const GValue *"));
+ set_prop.add_parameter (new CCodeFormalParameter ("pspec", "GParamSpec *"));
+
+ var block = new CCodeBlock ();
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null)));
+ ccall.add_argument (new CCodeIdentifier ("object"));
+ var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
+ block.add_statement (cdecl);
+
+ var cswitch = new CCodeSwitchStatement (new CCodeIdentifier ("property_id"));
+ var props = cl.get_properties ();
+ foreach (Property prop in props) {
+ if (prop.set_accessor == null || prop.is_abstract) {
+ continue;
+ }
+
+ bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
+
+ string prefix = cl.get_lower_case_cname (null);
+ if (is_virtual) {
+ prefix += "_real";
+ }
+
+ var ccase = new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ()));
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_set_%s".printf (prefix, prop.name)));
+ ccall.add_argument (new CCodeIdentifier ("self"));
+ var cgetcall = new CCodeFunctionCall ();
+ if (prop.type_reference.data_type is Class || prop.type_reference.data_type is Interface) {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_object");
+ } else if (prop.type_reference.type_name == "string") {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_string");
+ } else if (prop.type_reference.type_name == "int" || prop.type_reference.data_type is Enum) {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_int");
+ } else if (prop.type_reference.type_name == "uint") {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_uint");
+ } else if (prop.type_reference.type_name == "long") {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_long");
+ } else if (prop.type_reference.type_name == "ulong") {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_ulong");
+ } else if (prop.type_reference.type_name == "bool") {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_boolean");
+ } else if (prop.type_reference.type_name == "float") {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_float");
+ } else if (prop.type_reference.type_name == "double") {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_double");
+ } else {
+ cgetcall.call = new CCodeIdentifier ("g_value_get_pointer");
+ }
+ cgetcall.add_argument (new CCodeIdentifier ("value"));
+ ccall.add_argument (cgetcall);
+ ccase.add_statement (new CCodeExpressionStatement (ccall));
+ ccase.add_statement (new CCodeBreakStatement ());
+ cswitch.add_case (ccase);
+ }
+ block.add_statement (cswitch);
+
+ /* destroy func properties for generic types */
+ foreach (TypeParameter type_param in cl.get_type_parameters ()) {
+ string func_name = "%s_destroy_func".printf (type_param.name.down ());
+ string enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
+
+ var ccase = new CCodeCaseStatement (new CCodeIdentifier (enum_value));
+ var cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
+ var cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
+ cgetcall.add_argument (new CCodeIdentifier ("value"));
+ ccase.add_statement (new CCodeExpressionStatement (new CCodeAssignment (cfield, cgetcall)));
+ ccase.add_statement (new CCodeBreakStatement ());
+ cswitch.add_case (ccase);
+ }
+
+ set_prop.block = block;
+
+ source_type_member_definition.append (set_prop);
+ }
+
+ public override void visit_begin_struct (Struct! st) {
+ current_type_symbol = st.symbol;
+
+ instance_struct = new CCodeStruct ("_%s".printf (st.get_cname ()));
+
+ if (st.source_reference.file.cycle == null) {
+ header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (st.get_cname ()), new CCodeVariableDeclarator (st.get_cname ())));
+ }
+
+ if (st.source_reference.comment != null) {
+ header_type_definition.append (new CCodeComment (st.source_reference.comment));
+ }
+ header_type_definition.append (instance_struct);
+ }
+
+ public override void visit_end_struct (Struct! st) {
+ current_type_symbol = null;
+ }
+
+ public override void visit_begin_interface (Interface! iface) {
+ current_symbol = iface.symbol;
+ current_type_symbol = iface.symbol;
+
+ if (iface.is_static) {
+ return;
+ }
+
+ type_struct = new CCodeStruct ("_%s".printf (iface.get_type_cname ()));
+
+ header_type_declaration.append (new CCodeNewline ());
+ var macro = "(%s_get_type ())".printf (iface.get_lower_case_cname (null));
+ header_type_declaration.append (new CCodeMacroReplacement (iface.get_upper_case_cname ("TYPE_"), macro));
+
+ macro = "(G_TYPE_CHECK_INSTANCE_CAST ((obj), %s, %s))".printf (iface.get_upper_case_cname ("TYPE_"), iface.get_cname ());
+ header_type_declaration.append (new CCodeMacroReplacement ("%s(obj)".printf (iface.get_upper_case_cname (null)), macro));
+
+ macro = "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), %s))".printf (iface.get_upper_case_cname ("TYPE_"));
+ header_type_declaration.append (new CCodeMacroReplacement ("%s(obj)".printf (iface.get_upper_case_cname ("IS_")), macro));
+
+ macro = "(G_TYPE_INSTANCE_GET_INTERFACE ((obj), %s, %s))".printf (iface.get_upper_case_cname ("TYPE_"), iface.get_type_cname ());
+ header_type_declaration.append (new CCodeMacroReplacement ("%s_GET_INTERFACE(obj)".printf (iface.get_upper_case_cname (null)), macro));
+ header_type_declaration.append (new CCodeNewline ());
+
+
+ if (iface.source_reference.file.cycle == null) {
+ header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (iface.get_cname ()), new CCodeVariableDeclarator (iface.get_cname ())));
+ header_type_declaration.append (new CCodeTypeDefinition ("struct %s".printf (type_struct.name), new CCodeVariableDeclarator (iface.get_type_cname ())));
+ }
+
+ type_struct.add_field ("GTypeInterface", "parent");
+
+ if (iface.source_reference.comment != null) {
+ header_type_definition.append (new CCodeComment (iface.source_reference.comment));
+ }
+ header_type_definition.append (type_struct);
+ }
+
+ public override void visit_end_interface (Interface! iface) {
+ if (!iface.is_static) {
+ add_interface_base_init_function (iface);
+
+ var type_fun = new InterfaceRegisterFunction (iface);
+ type_fun.init_from_type ();
+ header_type_member_declaration.append (type_fun.get_declaration ());
+ source_type_member_definition.append (type_fun.get_definition ());
+ }
+
+ current_type_symbol = null;
+ }
+
+ private ref CCodeFunctionCall! get_param_spec (Property! prop) {
+ var cspec = new CCodeFunctionCall ();
+ cspec.add_argument (prop.get_canonical_cconstant ());
+ cspec.add_argument (new CCodeConstant ("\"foo\""));
+ cspec.add_argument (new CCodeConstant ("\"bar\""));
+ if (prop.type_reference.data_type is Class || prop.type_reference.data_type is Interface) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_object");
+ cspec.add_argument (new CCodeIdentifier (prop.type_reference.data_type.get_upper_case_cname ("TYPE_")));
+ } else if (prop.type_reference.data_type == string_type.data_type) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_string");
+ cspec.add_argument (new CCodeConstant ("NULL"));
+ } else if (prop.type_reference.data_type == int_type.data_type
+ || prop.type_reference.data_type is Enum) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_int");
+ cspec.add_argument (new CCodeConstant ("G_MININT"));
+ cspec.add_argument (new CCodeConstant ("G_MAXINT"));
+ cspec.add_argument (new CCodeConstant ("0"));
+ } else if (prop.type_reference.data_type == uint_type.data_type) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_uint");
+ cspec.add_argument (new CCodeConstant ("0"));
+ cspec.add_argument (new CCodeConstant ("G_MAXUINT"));
+ cspec.add_argument (new CCodeConstant ("0U"));
+ } else if (prop.type_reference.data_type == long_type.data_type) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_long");
+ cspec.add_argument (new CCodeConstant ("G_MINLONG"));
+ cspec.add_argument (new CCodeConstant ("G_MAXLONG"));
+ cspec.add_argument (new CCodeConstant ("0L"));
+ } else if (prop.type_reference.data_type == ulong_type.data_type) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_ulong");
+ cspec.add_argument (new CCodeConstant ("0"));
+ cspec.add_argument (new CCodeConstant ("G_MAXULONG"));
+ cspec.add_argument (new CCodeConstant ("0UL"));
+ } else if (prop.type_reference.data_type == bool_type.data_type) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_boolean");
+ cspec.add_argument (new CCodeConstant ("FALSE"));
+ } else if (prop.type_reference.data_type == float_type.data_type) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_float");
+ cspec.add_argument (new CCodeConstant ("-G_MAXFLOAT"));
+ cspec.add_argument (new CCodeConstant ("G_MAXFLOAT"));
+ cspec.add_argument (new CCodeConstant ("0.0F"));
+ } else if (prop.type_reference.data_type == double_type.data_type) {
+ cspec.call = new CCodeIdentifier ("g_param_spec_double");
+ cspec.add_argument (new CCodeConstant ("-G_MAXDOUBLE"));
+ cspec.add_argument (new CCodeConstant ("G_MAXDOUBLE"));
+ cspec.add_argument (new CCodeConstant ("0.0"));
+ } else {
+ cspec.call = new CCodeIdentifier ("g_param_spec_pointer");
+ }
+
+ var pflags = "G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB";
+ if (prop.get_accessor != null) {
+ pflags = "%s%s".printf (pflags, " | G_PARAM_READABLE");
+ }
+ if (prop.set_accessor != null) {
+ pflags = "%s%s".printf (pflags, " | G_PARAM_WRITABLE");
+ if (prop.set_accessor.construction) {
+ if (prop.set_accessor.writable) {
+ pflags = "%s%s".printf (pflags, " | G_PARAM_CONSTRUCT");
+ } else {
+ pflags = "%s%s".printf (pflags, " | G_PARAM_CONSTRUCT_ONLY");
+ }
+ }
+ }
+ cspec.add_argument (new CCodeConstant (pflags));
+
+ return cspec;
+ }
+
+ private ref CCodeFunctionCall! get_signal_creation (Signal! sig, DataType! type) {
+ var csignew = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_new"));
+ csignew.add_argument (new CCodeConstant ("\"%s\"".printf (sig.name)));
+ csignew.add_argument (new CCodeIdentifier (type.get_upper_case_cname ("TYPE_")));
+ csignew.add_argument (new CCodeConstant ("G_SIGNAL_RUN_LAST"));
+ csignew.add_argument (new CCodeConstant ("0"));
+ csignew.add_argument (new CCodeConstant ("NULL"));
+ csignew.add_argument (new CCodeConstant ("NULL"));
+
+ string marshaller = get_signal_marshaller_function (sig);
+
+ var marshal_arg = new CCodeIdentifier (marshaller);
+ csignew.add_argument (marshal_arg);
+
+ var params = sig.get_parameters ();
+ var params_len = params.length ();
+ if (sig.return_type.type_parameter != null) {
+ csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
+ } else if (sig.return_type.data_type == null) {
+ csignew.add_argument (new CCodeConstant ("G_TYPE_NONE"));
+ } else {
+ csignew.add_argument (new CCodeConstant (sig.return_type.data_type.get_type_id ()));
+ }
+ csignew.add_argument (new CCodeConstant ("%d".printf (params_len)));
+ foreach (FormalParameter param in params) {
+ if (param.type_reference.type_parameter != null) {
+ csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
+ } else {
+ csignew.add_argument (new CCodeConstant (param.type_reference.data_type.get_type_id ()));
+ }
+ }
+
+ marshal_arg.name = marshaller;
+
+ return csignew;
+ }
+
+ private void add_interface_base_init_function (Interface! iface) {
+ var base_init = new CCodeFunction ("%s_base_init".printf (iface.get_lower_case_cname (null)), "void");
+ base_init.add_parameter (new CCodeFormalParameter ("iface", "%sIface *".printf (iface.get_cname ())));
+ base_init.modifiers = CCodeModifiers.STATIC;
+
+ var init_block = new CCodeBlock ();
+
+ /* make sure not to run the initialization code twice */
+ base_init.block = new CCodeBlock ();
+ var decl = new CCodeDeclaration (bool_type.get_cname ());
+ decl.modifiers |= CCodeModifiers.STATIC;
+ decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("initialized", new CCodeConstant ("FALSE")));
+ base_init.block.add_statement (decl);
+ var cif = new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("initialized")), init_block);
+ base_init.block.add_statement (cif);
+ init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("initialized"), new CCodeConstant ("TRUE"))));
+
+ /* create properties */
+ var props = iface.get_properties ();
+ foreach (Property prop in props) {
+ var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_interface_install_property"));
+ cinst.add_argument (new CCodeIdentifier ("iface"));
+ cinst.add_argument (get_param_spec (prop));
+
+ init_block.add_statement (new CCodeExpressionStatement (cinst));
+ }
+
+ /* create signals */
+ foreach (Signal sig in iface.get_signals ()) {
+ init_block.add_statement (new CCodeExpressionStatement (get_signal_creation (sig, iface)));
+ }
+
+ source_type_member_definition.append (base_init);
+ }
+
+ public override void visit_begin_enum (Enum! en) {
+ cenum = new CCodeEnum (en.get_cname ());
+
+ if (en.source_reference.comment != null) {
+ header_type_definition.append (new CCodeComment (en.source_reference.comment));
+ }
+ header_type_definition.append (cenum);
+ }
+
+ public override void visit_enum_value (EnumValue! ev) {
+ string val;
+ if (ev.value is LiteralExpression) {
+ var lit = ((LiteralExpression) ev.value).literal;
+ if (lit is IntegerLiteral) {
+ val = ((IntegerLiteral) lit).value;
+ }
+ }
+ cenum.add_value (ev.get_cname (), val);
+ }
+
+ public override void visit_begin_flags (Flags! fl) {
+ cenum = new CCodeEnum (fl.get_cname ());
+
+ if (fl.source_reference.comment != null) {
+ header_type_definition.append (new CCodeComment (fl.source_reference.comment));
+ }
+ header_type_definition.append (cenum);
+ }
+
+ public override void visit_flags_value (FlagsValue! fv) {
+ string val;
+ if (fv.value is LiteralExpression) {
+ var lit = ((LiteralExpression) fv.value).literal;
+ if (lit is IntegerLiteral) {
+ val = ((IntegerLiteral) lit).value;
+ }
+ }
+ cenum.add_value (fv.get_cname (), val);
+ }
+
+ public override void visit_end_callback (Callback! cb) {
+ var cfundecl = new CCodeFunctionDeclarator (cb.get_cname ());
+ foreach (FormalParameter param in cb.get_parameters ()) {
+ cfundecl.add_parameter ((CCodeFormalParameter) param.ccodenode);
+ }
+
+ var ctypedef = new CCodeTypeDefinition (cb.return_type.get_cname (), cfundecl);
+
+ if (cb.access != MemberAccessibility.PRIVATE) {
+ header_type_declaration.append (ctypedef);
+ } else {
+ source_type_member_declaration.append (ctypedef);
+ }
+ }
+
+ public override void visit_member (Member! m) {
+ /* stuff meant for all lockable members */
+ if (m is Lockable && ((Lockable)m).get_lock_used ()) {
+ instance_priv_struct.add_field (mutex_type.get_cname (), get_symbol_lock_name (m.symbol));
+
+ instance_init_fragment.append (
+ new CCodeExpressionStatement (
+ new CCodeAssignment (
+ new CCodeMemberAccess.pointer (
+ new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"),
+ get_symbol_lock_name (m.symbol)),
+ new CCodeFunctionCall (new CCodeIdentifier (((Struct)mutex_type.data_type).default_construction_method.get_cname ())))));
+
+ var fc = new CCodeFunctionCall (new CCodeIdentifier ("VALA_FREE_CHECKED"));
+ fc.add_argument (
+ new CCodeMemberAccess.pointer (
+ new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"),
+ get_symbol_lock_name (m.symbol)));
+ fc.add_argument (new CCodeIdentifier (mutex_type.data_type.get_free_function ()));
+ if (instance_dispose_fragment != null) {
+ instance_dispose_fragment.append (new CCodeExpressionStatement (fc));
+ }
+ }
+ }
+
+ public override void visit_constant (Constant! c) {
+ if (c.symbol.parent_symbol.node is DataType) {
+ var t = (DataType) c.symbol.parent_symbol.node;
+ var cdecl = new CCodeDeclaration (c.type_reference.get_const_cname ());
+ var arr = "";
+ if (c.type_reference.data_type is Array) {
+ arr = "[]";
+ }
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("%s%s".printf (c.get_cname (), arr), (CCodeExpression) c.initializer.ccodenode));
+ cdecl.modifiers = CCodeModifiers.STATIC;
+
+ if (c.access != MemberAccessibility.PRIVATE) {
+ header_type_member_declaration.append (cdecl);
+ } else {
+ source_type_member_declaration.append (cdecl);
+ }
+ }
+ }
+
+ public override void visit_field (Field! f) {
+ CCodeExpression lhs = null;
+ CCodeStruct st = null;
+
+ if (f.access != MemberAccessibility.PRIVATE) {
+ st = instance_struct;
+ if (f.instance) {
+ lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), f.get_cname ());
+ }
+ } else if (f.access == MemberAccessibility.PRIVATE) {
+ if (f.instance) {
+ st = instance_priv_struct;
+ lhs = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), f.get_cname ());
+ } else {
+ if (f.symbol.parent_symbol.node is DataType) {
+ var t = (DataType) f.symbol.parent_symbol.node;
+ var cdecl = new CCodeDeclaration (f.type_reference.get_cname ());
+ var var_decl = new CCodeVariableDeclarator (f.get_cname ());
+ if (f.initializer != null) {
+ var_decl.initializer = (CCodeExpression) f.initializer.ccodenode;
+ }
+ cdecl.add_declarator (var_decl);
+ cdecl.modifiers = CCodeModifiers.STATIC;
+ source_type_member_declaration.append (cdecl);
+ }
+ }
+ }
+
+ if (f.instance) {
+ st.add_field (f.type_reference.get_cname (), f.get_cname ());
+ if (f.type_reference.data_type is Array && !f.no_array_length) {
+ // create fields to store array dimensions
+ var arr = (Array) f.type_reference.data_type;
+
+ for (int dim = 1; dim <= arr.rank; dim++) {
+ var len_type = new TypeReference ();
+ len_type.data_type = int_type.data_type;
+
+ st.add_field (len_type.get_cname (), get_array_length_cname (f.name, dim));
+ }
+ }
+
+ if (f.initializer != null) {
+ instance_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (lhs, (CCodeExpression) f.initializer.ccodenode)));
+
+ if (f.type_reference.data_type is Array && !f.no_array_length &&
+ f.initializer is ArrayCreationExpression) {
+ var ma = new MemberAccess.simple (f.name);
+ ma.symbol_reference = f.symbol;
+
+ var array_len_lhs = get_array_length_cexpression (ma, 1);
+ var sizes = ((ArrayCreationExpression) f.initializer).get_sizes ();
+ var size = (Expression) sizes.data;
+ instance_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (array_len_lhs, (CCodeExpression) size.ccodenode)));
+ }
+ }
+
+ if (f.type_reference.takes_ownership && instance_dispose_fragment != null) {
+ instance_dispose_fragment.append (new CCodeExpressionStatement (get_unref_expression (lhs, f.type_reference)));
+ }
+ }
+ }
+
+ public override void visit_begin_method (Method! m) {
+ current_symbol = m.symbol;
+ current_return_type = m.return_type;
+ }
+
+ private ref CCodeStatement create_method_type_check_statement (Method! m, DataType! t, bool non_null, string! var_name) {
+ return create_type_check_statement (m, m.return_type.data_type, t, non_null, var_name);
+ }
+
+ private ref CCodeStatement create_property_type_check_statement (Property! prop, bool getter, DataType! t, bool non_null, string! var_name) {
+ if (getter) {
+ return create_type_check_statement (prop, prop.type_reference.data_type, t, non_null, var_name);
+ } else {
+ return create_type_check_statement (prop, null, t, non_null, var_name);
+ }
+ }
+
+ private ref CCodeStatement create_type_check_statement (CodeNode! method_node, DataType ret_type, DataType! t, bool non_null, string! var_name) {
+ var ccheck = new CCodeFunctionCall ();
+
+ if (t is Class || t is Interface) {
+ var ctype_check = new CCodeFunctionCall (new CCodeIdentifier (t.get_upper_case_cname ("IS_")));
+ ctype_check.add_argument (new CCodeIdentifier (var_name));
+
+ ref CCodeExpression cexpr = ctype_check;
+ if (!non_null) {
+ var cnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (var_name), new CCodeConstant ("NULL"));
+
+ cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cnull, ctype_check);
+ }
+ ccheck.add_argument (cexpr);
+ } else if (!non_null) {
+ return null;
+ } else {
+ var cnonnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier (var_name), new CCodeConstant ("NULL"));
+ ccheck.add_argument (cnonnull);
+ }
+
+ if (ret_type == null) {
+ /* void function */
+ ccheck.call = new CCodeIdentifier ("g_return_if_fail");
+ } else {
+ ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
+
+ if (ret_type.is_reference_type () || ret_type is Pointer) {
+ ccheck.add_argument (new CCodeConstant ("NULL"));
+ } else if (ret_type.get_default_value () != null) {
+ ccheck.add_argument (new CCodeConstant (ret_type.get_default_value ()));
+ } else {
+ Report.warning (method_node.source_reference, "not supported return type for runtime type checks");
+ return new CCodeExpressionStatement (new CCodeConstant ("0"));
+ }
+ }
+
+ return new CCodeExpressionStatement (ccheck);
+ }
+
+ private DataType find_parent_type (CodeNode node) {
+ var sym = node.symbol;
+ while (sym != null) {
+ if (sym.node is DataType) {
+ return (DataType) sym.node;
+ }
+ sym = sym.parent_symbol;
+ }
+ return null;
+ }
+
+ private ref string! get_array_length_cname (string! array_cname, int dim) {
+ return "%s_length%d".printf (array_cname, dim);
+ }
+
+ public override void visit_end_method (Method! m) {
+ current_symbol = current_symbol.parent_symbol;
+ current_return_type = null;
+
+ if (current_type_symbol != null && current_type_symbol.node is Interface) {
+ var iface = (Interface) current_type_symbol.node;
+ if (iface.is_static) {
+ return;
+ }
+ }
+
+ if (current_symbol.parent_symbol != null &&
+ current_symbol.parent_symbol.node is Method) {
+ /* lambda expressions produce nested methods */
+ var up_method = (Method) current_symbol.parent_symbol.node;
+ current_return_type = up_method.return_type;
+ }
+
+ function = new CCodeFunction (m.get_real_cname (), m.return_type.get_cname ());
+ CCodeFunctionDeclarator vdeclarator = null;
+
+ CCodeFormalParameter instance_param = null;
+
+ if (m.instance) {
+ var this_type = new TypeReference ();
+ this_type.data_type = find_parent_type (m);
+ if (m.base_interface_method != null) {
+ var base_type = new TypeReference ();
+ base_type.data_type = (DataType) m.base_interface_method.symbol.parent_symbol.node;
+ instance_param = new CCodeFormalParameter ("base", base_type.get_cname ());
+ } else if (m.overrides) {
+ var base_type = new TypeReference ();
+ base_type.data_type = (DataType) m.base_method.symbol.parent_symbol.node;
+ instance_param = new CCodeFormalParameter ("base", base_type.get_cname ());
+ } else {
+ if (m.instance_by_reference) {
+ instance_param = new CCodeFormalParameter ("*self", this_type.get_cname ());
+ } else {
+ instance_param = new CCodeFormalParameter ("self", this_type.get_cname ());
+ }
+ }
+ if (!m.instance_last) {
+ function.add_parameter (instance_param);
+ }
+
+ if (m.is_abstract || m.is_virtual) {
+ var vdecl = new CCodeDeclaration (m.return_type.get_cname ());
+ vdeclarator = new CCodeFunctionDeclarator (m.name);
+ vdecl.add_declarator (vdeclarator);
+ type_struct.add_declaration (vdecl);
+
+ vdeclarator.add_parameter (instance_param);
+ }
+ }
+
+ if (m is CreationMethod && current_class != null) {
+ // memory management for generic types
+ foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
+ var cparam = new CCodeFormalParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify");
+ function.add_parameter (cparam);
+ }
+ }
+
+ var params = m.get_parameters ();
+ foreach (FormalParameter param in params) {
+ if (!param.no_array_length && param.type_reference.data_type is Array) {
+ var arr = (Array) param.type_reference.data_type;
+
+ var length_ctype = "int";
+ if (param.type_reference.is_out) {
+ length_ctype = "int*";
+ }
+
+ for (int dim = 1; dim <= arr.rank; dim++) {
+ var cparam = new CCodeFormalParameter (get_array_length_cname (param.name, dim), length_ctype);
+ function.add_parameter (cparam);
+ if (vdeclarator != null) {
+ vdeclarator.add_parameter (cparam);
+ }
+ }
+ }
+
+ function.add_parameter ((CCodeFormalParameter) param.ccodenode);
+ if (vdeclarator != null) {
+ vdeclarator.add_parameter ((CCodeFormalParameter) param.ccodenode);
+ }
+ }
+
+ if (m.instance && m.instance_last) {
+ function.add_parameter (instance_param);
+ }
+
+ /* real function declaration and definition not needed
+ * for abstract methods */
+ if (!m.is_abstract) {
+ if (m.access != MemberAccessibility.PRIVATE && m.base_method == null && m.base_interface_method == null) {
+ /* public methods need function declaration in
+ * header file except virtual/overridden methods */
+ header_type_member_declaration.append (function.copy ());
+ } else {
+ /* declare all other functions in source file to
+ * avoid dependency on order within source file */
+ function.modifiers |= CCodeModifiers.STATIC;
+ source_type_member_declaration.append (function.copy ());
+ }
+
+ /* Methods imported from a plain C file don't
+ * have a body, e.g. Vala.Parser.parse_file () */
+ if (m.body != null) {
+ function.block = (CCodeBlock) m.body.ccodenode;
+
+ var cinit = new CCodeFragment ();
+ function.block.prepend_statement (cinit);
+
+ if (m.symbol.parent_symbol.node is Class) {
+ var cl = (Class) m.symbol.parent_symbol.node;
+ if (m.overrides || m.base_interface_method != null) {
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null)));
+ ccall.add_argument (new CCodeIdentifier ("base"));
+
+ var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
+
+ cinit.append (cdecl);
+ } else if (m.instance) {
+ cinit.append (create_method_type_check_statement (m, cl, true, "self"));
+ }
+ }
+ foreach (FormalParameter param in m.get_parameters ()) {
+ var t = param.type_reference.data_type;
+ if (t != null && t.is_reference_type () && !param.type_reference.is_out) {
+ var type_check = create_method_type_check_statement (m, t, param.type_reference.non_null, param.name);
+ if (type_check != null) {
+ cinit.append (type_check);
+ }
+ }
+ }
+
+ if (m.source_reference != null && m.source_reference.comment != null) {
+ source_type_member_definition.append (new CCodeComment (m.source_reference.comment));
+ }
+ source_type_member_definition.append (function);
+
+ if (m is CreationMethod) {
+ if (current_class != null) {
+ int n_params = ((CreationMethod) m).n_construction_params;
+ n_params += (int) current_class.get_type_parameters ().length ();
+
+ // declare construction parameter array
+ var cparamsinit = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
+ cparamsinit.add_argument (new CCodeIdentifier ("GParameter"));
+ cparamsinit.add_argument (new CCodeConstant (n_params.to_string ()));
+
+ var cdecl = new CCodeDeclaration ("GParameter *");
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("__params", cparamsinit));
+ cinit.append (cdecl);
+
+ cdecl = new CCodeDeclaration ("GParameter *");
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("__params_it", new CCodeIdentifier ("__params")));
+ cinit.append (cdecl);
+
+ /* destroy func properties for generic types */
+ foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
+ string func_name = "%s_destroy_func".printf (type_param.name.down ());
+ var func_name_constant = new CCodeConstant ("\"%s-destroy-func\"".printf (type_param.name.down ()));
+
+ // this property is used as a construction parameter
+ var cpointer = new CCodeIdentifier ("__params_it");
+
+ var ccomma = new CCodeCommaExpression ();
+ // set name in array for current parameter
+ var cnamemember = new CCodeMemberAccess.pointer (cpointer, "name");
+ ccomma.append_expression (new CCodeAssignment (cnamemember, func_name_constant));
+ var gvaluearg = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (cpointer, "value"));
+
+ // initialize GValue in array for current parameter
+ var cvalueinit = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
+ cvalueinit.add_argument (gvaluearg);
+ cvalueinit.add_argument (new CCodeIdentifier ("G_TYPE_POINTER"));
+ ccomma.append_expression (cvalueinit);
+
+ // set GValue for current parameter
+ var cvalueset = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
+ cvalueset.add_argument (gvaluearg);
+ cvalueset.add_argument (new CCodeIdentifier (func_name));
+ ccomma.append_expression (cvalueset);
+
+ // move pointer to next parameter in array
+ ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, cpointer));
+
+ cinit.append (new CCodeExpressionStatement (ccomma));
+ }
+ } else {
+ var st = (Struct) m.symbol.parent_symbol.node;
+ var cdecl = new CCodeDeclaration (st.get_cname () + "*");
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
+ ccall.add_argument (new CCodeConstant (st.get_cname ()));
+ ccall.add_argument (new CCodeConstant ("1"));
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
+ cinit.append (cdecl);
+ }
+ }
+
+ if (context.module_init_method == m && in_plugin) {
+ // GTypeModule-based plug-in, register types
+ cinit.append (module_init_fragment);
+ }
+ }
+ }
+
+ if (m.is_abstract || m.is_virtual) {
+ var vfunc = new CCodeFunction (m.get_cname (), m.return_type.get_cname ());
+
+ var this_type = new TypeReference ();
+ this_type.data_type = (DataType) m.symbol.parent_symbol.node;
+
+ var cparam = new CCodeFormalParameter ("self", this_type.get_cname ());
+ vfunc.add_parameter (cparam);
+
+ var vblock = new CCodeBlock ();
+
+ CCodeFunctionCall vcast = null;
+ if (m.symbol.parent_symbol.node is Interface) {
+ var iface = (Interface) m.symbol.parent_symbol.node;
+
+ vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (iface.get_upper_case_cname (null))));
+ } else {
+ var cl = (Class) m.symbol.parent_symbol.node;
+
+ vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (cl.get_upper_case_cname (null))));
+ }
+ vcast.add_argument (new CCodeIdentifier ("self"));
+
+ var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, m.name));
+ vcall.add_argument (new CCodeIdentifier ("self"));
+
+ var params = m.get_parameters ();
+ foreach (FormalParameter param in params) {
+ vfunc.add_parameter ((CCodeFormalParameter) param.ccodenode);
+ vcall.add_argument (new CCodeIdentifier (param.name));
+ }
+
+ if (m.return_type.data_type == null) {
+ vblock.add_statement (new CCodeExpressionStatement (vcall));
+ } else {
+ /* pass method return value */
+ vblock.add_statement (new CCodeReturnStatement (vcall));
+ }
+
+ header_type_member_declaration.append (vfunc.copy ());
+
+ vfunc.block = vblock;
+
+ source_type_member_definition.append (vfunc);
+ }
+
+ if (m is CreationMethod) {
+ var creturn = new CCodeReturnStatement ();
+ creturn.return_expression = new CCodeIdentifier ("self");
+ function.block.add_statement (creturn);
+ }
+
+ bool return_value = true;
+ bool args_parameter = true;
+ if (is_possible_entry_point (m, ref return_value, ref args_parameter)) {
+ // m is possible entry point, add appropriate startup code
+ var cmain = new CCodeFunction ("main", "int");
+ cmain.add_parameter (new CCodeFormalParameter ("argc", "int"));
+ cmain.add_parameter (new CCodeFormalParameter ("argv", "char **"));
+ var main_block = new CCodeBlock ();
+ main_block.add_statement (new CCodeExpressionStatement (new CCodeFunctionCall (new CCodeIdentifier ("g_type_init"))));
+ var main_call = new CCodeFunctionCall (new CCodeIdentifier (function.name));
+ if (args_parameter) {
+ main_call.add_argument (new CCodeIdentifier ("argc"));
+ main_call.add_argument (new CCodeIdentifier ("argv"));
+ }
+ if (return_value) {
+ main_block.add_statement (new CCodeReturnStatement (main_call));
+ } else {
+ // method returns void, always use 0 as exit code
+ main_block.add_statement (new CCodeExpressionStatement (main_call));
+ main_block.add_statement (new CCodeReturnStatement (new CCodeConstant ("0")));
+ }
+ cmain.block = main_block;
+ source_type_member_definition.append (cmain);
+ }
+ }
+
+ public override void visit_begin_creation_method (CreationMethod! m) {
+ current_symbol = m.symbol;
+ current_return_type = m.return_type;
+ in_creation_method = true;
+ }
+
+ public override void visit_end_creation_method (CreationMethod! m) {
+ if (current_class != null && m.body != null) {
+ add_object_creation ((CCodeBlock) m.body.ccodenode);
+ }
+
+ in_creation_method = false;
+
+ visit_end_method (m);
+ }
+
+ private bool is_possible_entry_point (Method! m, ref bool return_value, ref bool args_parameter) {
+ if (m.name == null || m.name != "main") {
+ // method must be called "main"
+ return false;
+ }
+
+ if (m.instance) {
+ // method must be static
+ return false;
+ }
+
+ if (m.return_type.data_type == null) {
+ return_value = false;
+ } else if (m.return_type.data_type == int_type.data_type) {
+ return_value = true;
+ } else {
+ // return type must be void or int
+ return false;
+ }
+
+ var params = m.get_parameters ();
+ if (params.length () == 0) {
+ // method may have no parameters
+ args_parameter = false;
+ return true;
+ }
+
+ if (params.length () > 1) {
+ // method must not have more than one parameter
+ return false;
+ }
+
+ var param = (FormalParameter) params.data;
+
+ if (param.type_reference.is_out) {
+ // parameter must not be an out parameter
+ return false;
+ }
+
+ if (!(param.type_reference.data_type is Array)) {
+ // parameter must be an array
+ return false;
+ }
+
+ var array_type = (Array) param.type_reference.data_type;
+ if (array_type.element_type != string_type.data_type) {
+ // parameter must be an array of strings
+ return false;
+ }
+
+ args_parameter = true;
+ return true;
+ }
+
+ public override void visit_formal_parameter (FormalParameter! p) {
+ if (!p.ellipsis) {
+ p.ccodenode = new CCodeFormalParameter (p.name, p.type_reference.get_cname (false, !p.type_reference.takes_ownership));
+ }
+ }
+
+ public override void visit_end_property (Property! prop) {
+ prop_enum.add_value (prop.get_upper_case_cname (), null);
+ }
+
+ public override void visit_begin_property_accessor (PropertyAccessor! acc) {
+ var prop = (Property) acc.symbol.parent_symbol.node;
+
+ if (acc.readable) {
+ current_return_type = prop.type_reference;
+ } else {
+ // void
+ current_return_type = new TypeReference ();
+ }
+ }
+
+ public override void visit_end_property_accessor (PropertyAccessor! acc) {
+ var prop = (Property) acc.symbol.parent_symbol.node;
+
+ current_return_type = null;
+
+ var t = (DataType) prop.symbol.parent_symbol.node;
+
+ var this_type = new TypeReference ();
+ this_type.data_type = t;
+ var cselfparam = new CCodeFormalParameter ("self", this_type.get_cname ());
+ var cvalueparam = new CCodeFormalParameter ("value", prop.type_reference.get_cname (false, true));
+
+ if (prop.is_abstract || prop.is_virtual) {
+ if (acc.readable) {
+ function = new CCodeFunction ("%s_get_%s".printf (t.get_lower_case_cname (null), prop.name), prop.type_reference.get_cname ());
+ } else {
+ function = new CCodeFunction ("%s_set_%s".printf (t.get_lower_case_cname (null), prop.name), "void");
+ }
+ function.add_parameter (cselfparam);
+ if (acc.writable || acc.construction) {
+ function.add_parameter (cvalueparam);
+ }
+
+ header_type_member_declaration.append (function.copy ());
+
+ var block = new CCodeBlock ();
+ function.block = block;
+
+ if (acc.readable) {
+ // declare temporary variable to save the property value
+ var decl = new CCodeDeclaration (prop.type_reference.get_cname ());
+ decl.add_declarator (new CCodeVariableDeclarator ("value"));
+ block.add_statement (decl);
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
+
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
+ ccast.add_argument (new CCodeIdentifier ("self"));
+ ccall.add_argument (ccast);
+
+ // property name is second argument of g_object_get
+ ccall.add_argument (prop.get_canonical_cconstant ());
+
+ ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("value")));
+
+ ccall.add_argument (new CCodeConstant ("NULL"));
+
+ block.add_statement (new CCodeExpressionStatement (ccall));
+ block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("value")));
+ } else {
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set"));
+
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
+ ccast.add_argument (new CCodeIdentifier ("self"));
+ ccall.add_argument (ccast);
+
+ // property name is second argument of g_object_set
+ ccall.add_argument (prop.get_canonical_cconstant ());
+
+ ccall.add_argument (new CCodeIdentifier ("value"));
+
+ ccall.add_argument (new CCodeConstant ("NULL"));
+
+ block.add_statement (new CCodeExpressionStatement (ccall));
+ }
+
+ source_type_member_definition.append (function);
+ }
+
+ if (!prop.is_abstract) {
+ bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
+
+ string prefix = t.get_lower_case_cname (null);
+ if (is_virtual) {
+ prefix += "_real";
+ }
+ if (acc.readable) {
+ function = new CCodeFunction ("%s_get_%s".printf (prefix, prop.name), prop.type_reference.get_cname ());
+ } else {
+ function = new CCodeFunction ("%s_set_%s".printf (prefix, prop.name), "void");
+ }
+ if (is_virtual) {
+ function.modifiers |= CCodeModifiers.STATIC;
+ }
+ function.add_parameter (cselfparam);
+ if (acc.writable || acc.construction) {
+ function.add_parameter (cvalueparam);
+ }
+
+ if (!is_virtual) {
+ header_type_member_declaration.append (function.copy ());
+ }
+
+ if (acc.body != null) {
+ function.block = (CCodeBlock) acc.body.ccodenode;
+
+ function.block.prepend_statement (create_property_type_check_statement (prop, acc.readable, t, true, "self"));
+ }
+
+ source_type_member_definition.append (function);
+ }
+ }
+
+ private string get_marshaller_type_name (TypeReference t) {
+ if (t.type_parameter != null) {
+ return ("POINTER");
+ } else if (t.data_type == null) {
+ return ("VOID");
+ } else {
+ return t.data_type.get_marshaller_type_name ();
+ }
+ }
+
+ private ref string get_signal_marshaller_function (Signal! sig, string prefix = null) {
+ var signature = get_signal_signature (sig);
+ string ret;
+ var params = sig.get_parameters ();
+
+ if (prefix == null) {
+ // FIXME remove equality check with cast in next revision
+ if (predefined_marshal_list.lookup (signature) != (bool) null) {
+ prefix = "g_cclosure_marshal";
+ } else {
+ prefix = "g_cclosure_user_marshal";
+ }
+ }
+
+ ret = "%s_%s_".printf (prefix, get_marshaller_type_name (sig.return_type));
+
+ if (params == null) {
+ ret = ret + "_VOID";
+ } else {
+ foreach (FormalParameter p in params) {
+ ret = "%s_%s".printf (ret, get_marshaller_type_name (p.type_reference));
+ }
+ }
+
+ return ret;
+ }
+
+ private string get_value_type_name_from_type_reference (TypeReference! t) {
+ if (t.type_parameter != null) {
+ return "gpointer";
+ } else if (t.data_type == null) {
+ return "void";
+ } else if (t.data_type is Class || t.data_type is Interface) {
+ return "GObject *";
+ } else if (t.data_type is Struct) {
+ if (((Struct) t.data_type).is_reference_type ()) {
+ return "gpointer";
+ } else {
+ return t.data_type.get_cname ();
+ }
+ } else if (t.data_type is Enum) {
+ return "gint";
+ } else if (t.data_type is Flags) {
+ return "guint";
+ } else if (t.data_type is Array) {
+ return "gpointer";
+ }
+
+ return null;
+ }
+
+ private ref string get_signal_signature (Signal! sig) {
+ string signature;
+ var params = sig.get_parameters ();
+
+ signature = "%s:".printf (get_marshaller_type_name (sig.return_type));
+ if (params == null) {
+ signature = signature + "VOID";
+ } else {
+ bool first = true;
+ foreach (FormalParameter p in params) {
+ if (first) {
+ signature = signature + get_marshaller_type_name (p.type_reference);
+ first = false;
+ } else {
+ signature = "%s,%s".printf (signature, get_marshaller_type_name (p.type_reference));
+ }
+ }
+ }
+
+ return signature;
+ }
+
+ public override void visit_end_signal (Signal! sig) {
+ string signature;
+ var params = sig.get_parameters ();
+ int n_params, i;
+
+ /* check whether a signal with the same signature already exists for this source file (or predefined) */
+ signature = get_signal_signature (sig);
+ // FIXME remove equality checks with cast in next revision
+ if (predefined_marshal_list.lookup (signature) != (bool) null || user_marshal_list.lookup (signature) != (bool) null) {
+ return;
+ }
+
+ var signal_marshaller = new CCodeFunction (get_signal_marshaller_function (sig), "void");
+ signal_marshaller.modifiers = CCodeModifiers.STATIC;
+
+ signal_marshaller.add_parameter (new CCodeFormalParameter ("closure", "GClosure *"));
+ signal_marshaller.add_parameter (new CCodeFormalParameter ("return_value", "GValue *"));
+ signal_marshaller.add_parameter (new CCodeFormalParameter ("n_param_values", "guint"));
+ signal_marshaller.add_parameter (new CCodeFormalParameter ("param_values", "const GValue *"));
+ signal_marshaller.add_parameter (new CCodeFormalParameter ("invocation_hint", "gpointer"));
+ signal_marshaller.add_parameter (new CCodeFormalParameter ("marshal_data", "gpointer"));
+
+ source_signal_marshaller_declaration.append (signal_marshaller.copy ());
+
+ var marshaller_body = new CCodeBlock ();
+
+ var callback_decl = new CCodeFunctionDeclarator (get_signal_marshaller_function (sig, "GMarshalFunc"));
+ callback_decl.add_parameter (new CCodeFormalParameter ("data1", "gpointer"));
+ n_params = 1;
+ foreach (FormalParameter p in params) {
+ callback_decl.add_parameter (new CCodeFormalParameter ("arg_%d".printf (n_params), get_value_type_name_from_type_reference (p.type_reference)));
+ n_params++;
+ }
+ callback_decl.add_parameter (new CCodeFormalParameter ("data2", "gpointer"));
+ marshaller_body.add_statement (new CCodeTypeDefinition (get_value_type_name_from_type_reference (sig.return_type), callback_decl));
+
+ var var_decl = new CCodeDeclaration (get_signal_marshaller_function (sig, "GMarshalFunc"));
+ var_decl.modifiers = CCodeModifiers.REGISTER;
+ var_decl.add_declarator (new CCodeVariableDeclarator ("callback"));
+ marshaller_body.add_statement (var_decl);
+
+ var_decl = new CCodeDeclaration ("GCClosure *");
+ var_decl.modifiers = CCodeModifiers.REGISTER;
+ var_decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("cc", new CCodeCastExpression (new CCodeIdentifier ("closure"), "GCClosure *")));
+ marshaller_body.add_statement (var_decl);
+
+ var_decl = new CCodeDeclaration ("gpointer");
+ var_decl.modifiers = CCodeModifiers.REGISTER;
+ var_decl.add_declarator (new CCodeVariableDeclarator ("data1"));
+ var_decl.add_declarator (new CCodeVariableDeclarator ("data2"));
+ marshaller_body.add_statement (var_decl);
+
+ CCodeFunctionCall fc;
+
+ if (sig.return_type.data_type != null) {
+ var_decl = new CCodeDeclaration (get_value_type_name_from_type_reference (sig.return_type));
+ var_decl.add_declarator (new CCodeVariableDeclarator ("v_return"));
+ marshaller_body.add_statement (var_decl);
+
+ fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
+ fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("return_value"), new CCodeConstant ("NULL")));
+ marshaller_body.add_statement (new CCodeExpressionStatement (fc));
+ }
+
+ fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
+ fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("n_param_values"), new CCodeConstant (n_params.to_string())));
+ marshaller_body.add_statement (new CCodeExpressionStatement (fc));
+
+ var data = new CCodeMemberAccess (new CCodeIdentifier ("closure"), "data", true);
+ var param = new CCodeMemberAccess (new CCodeMemberAccess (new CCodeIdentifier ("param_values"), "data[0]", true), "v_pointer");
+ var cond = new CCodeFunctionCall (new CCodeConstant ("G_CCLOSURE_SWAP_DATA"));
+ cond.add_argument (new CCodeIdentifier ("closure"));
+ var true_block = new CCodeBlock ();
+ true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data1"), data)));
+ true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data2"), param)));
+ var false_block = new CCodeBlock ();
+ false_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data1"), param)));
+ false_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data2"), data)));
+ marshaller_body.add_statement (new CCodeIfStatement (cond, true_block, false_block));
+
+ var c_assign = new CCodeAssignment (new CCodeIdentifier ("callback"), new CCodeCastExpression (new CCodeConditionalExpression (new CCodeIdentifier ("marshal_data"), new CCodeIdentifier ("marshal_data"), new CCodeMemberAccess (new CCodeIdentifier ("cc"), "callback", true)), get_signal_marshaller_function (sig, "GMarshalFunc")));
+ marshaller_body.add_statement (new CCodeExpressionStatement (c_assign));
+
+ fc = new CCodeFunctionCall (new CCodeIdentifier ("callback"));
+ fc.add_argument (new CCodeIdentifier ("data1"));
+ i = 1;
+ foreach (FormalParameter p in params) {
+ string get_value_function;
+ if (p.type_reference.type_parameter != null) {
+ get_value_function = "g_value_get_pointer";
+ } else {
+ get_value_function = p.type_reference.data_type.get_get_value_function ();
+ }
+ var inner_fc = new CCodeFunctionCall (new CCodeIdentifier (get_value_function));
+ inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ())));
+ fc.add_argument (inner_fc);
+ i++;
+ }
+ fc.add_argument (new CCodeIdentifier ("data2"));
+
+ if (sig.return_type.data_type != null) {
+ marshaller_body.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("v_return"), fc)));
+
+ CCodeFunctionCall set_fc;
+ if (sig.return_type.type_parameter != null) {
+ set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
+ } else if (sig.return_type.data_type is Class || sig.return_type.data_type is Interface) {
+ set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_object"));
+ } else if (sig.return_type.data_type == string_type.data_type) {
+ set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_string"));
+ } else {
+ set_fc = new CCodeFunctionCall (new CCodeIdentifier (sig.return_type.data_type.get_set_value_function ()));
+ }
+ set_fc.add_argument (new CCodeIdentifier ("return_value"));
+ set_fc.add_argument (new CCodeIdentifier ("v_return"));
+
+ marshaller_body.add_statement (new CCodeExpressionStatement (set_fc));
+ } else {
+ marshaller_body.add_statement (new CCodeExpressionStatement (fc));
+ }
+
+ signal_marshaller.block = marshaller_body;
+
+ source_signal_marshaller_definition.append (signal_marshaller);
+ user_marshal_list.insert (signature, true);
+ }
+
+ public override void visit_end_constructor (Constructor! c) {
+ var cl = (Class) c.symbol.parent_symbol.node;
+
+ function = new CCodeFunction ("%s_constructor".printf (cl.get_lower_case_cname (null)), "GObject *");
+ function.modifiers = CCodeModifiers.STATIC;
+
+ function.add_parameter (new CCodeFormalParameter ("type", "GType"));
+ function.add_parameter (new CCodeFormalParameter ("n_construct_properties", "guint"));
+ function.add_parameter (new CCodeFormalParameter ("construct_properties", "GObjectConstructParam *"));
+
+ source_type_member_declaration.append (function.copy ());
+
+
+ var cblock = new CCodeBlock ();
+ var cdecl = new CCodeDeclaration ("GObject *");
+ cdecl.add_declarator (new CCodeVariableDeclarator ("obj"));
+ cblock.add_statement (cdecl);
+
+ cdecl = new CCodeDeclaration ("%sClass *".printf (cl.get_cname ()));
+ cdecl.add_declarator (new CCodeVariableDeclarator ("klass"));
+ cblock.add_statement (cdecl);
+
+ cdecl = new CCodeDeclaration ("GObjectClass *");
+ cdecl.add_declarator (new CCodeVariableDeclarator ("parent_class"));
+ cblock.add_statement (cdecl);
+
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek"));
+ ccall.add_argument (new CCodeIdentifier (cl.get_upper_case_cname ("TYPE_")));
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (cl.get_upper_case_cname (null))));
+ ccast.add_argument (ccall);
+ cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("klass"), ccast)));
+
+ ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek_parent"));
+ ccall.add_argument (new CCodeIdentifier ("klass"));
+ ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
+ ccast.add_argument (ccall);
+ cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("parent_class"), ccast)));
+
+
+ ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("parent_class"), "constructor"));
+ ccall.add_argument (new CCodeIdentifier ("type"));
+ ccall.add_argument (new CCodeIdentifier ("n_construct_properties"));
+ ccall.add_argument (new CCodeIdentifier ("construct_properties"));
+ cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("obj"), ccall)));
+
+
+ ccall = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null)));
+ ccall.add_argument (new CCodeIdentifier ("obj"));
+
+ cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
+
+ cblock.add_statement (cdecl);
+
+
+ cblock.add_statement (c.body.ccodenode);
+
+ cblock.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("obj")));
+
+ function.block = cblock;
+
+ if (c.source_reference.comment != null) {
+ source_type_member_definition.append (new CCodeComment (c.source_reference.comment));
+ }
+ source_type_member_definition.append (function);
+ }
+
+ public override void visit_begin_block (Block! b) {
+ current_symbol = b.symbol;
+ }
+
+ private void add_object_creation (CCodeBlock! b) {
+ var cl = (Class) current_type_symbol.node;
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_newv"));
+ ccall.add_argument (new CCodeConstant (cl.get_type_id ()));
+ ccall.add_argument (new CCodeConstant ("__params_it - __params"));
+ ccall.add_argument (new CCodeConstant ("__params"));
+
+ var cdecl = new CCodeVariableDeclarator ("self");
+ cdecl.initializer = ccall;
+
+ var cdeclaration = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
+ cdeclaration.add_declarator (cdecl);
+
+ b.add_statement (cdeclaration);
+ }
+
+ public override void visit_end_block (Block! b) {
+ var local_vars = b.get_local_variables ();
+ foreach (VariableDeclarator decl in local_vars) {
+ decl.symbol.active = false;
+ }
+
+ var cblock = new CCodeBlock ();
+
+ foreach (Statement stmt in b.get_statements ()) {
+ var src = stmt.source_reference;
+ if (src != null && src.comment != null) {
+ cblock.add_statement (new CCodeComment (src.comment));
+ }
+
+ if (stmt.ccodenode is CCodeFragment) {
+ foreach (CCodeStatement cstmt in ((CCodeFragment) stmt.ccodenode).get_children ()) {
+ cblock.add_statement (cstmt);
+ }
+ } else {
+ cblock.add_statement ((CCodeStatement) stmt.ccodenode);
+ }
+ }
+
+ if (memory_management) {
+ foreach (VariableDeclarator decl in local_vars) {
+ if (decl.type_reference.takes_ownership) {
+ cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference)));
+ }
+ }
+ }
+
+ b.ccodenode = cblock;
+
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_empty_statement (EmptyStatement! stmt) {
+ stmt.ccodenode = new CCodeEmptyStatement ();
+ }
+
+ private bool struct_has_instance_fields (Struct! st) {
+ foreach (Field f in st.get_fields ()) {
+ if (f.instance) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public override void visit_declaration_statement (DeclarationStatement! stmt) {
+ /* split declaration statement as var declarators
+ * might have different types */
+
+ var cfrag = new CCodeFragment ();
+
+ foreach (VariableDeclarator decl in stmt.declaration.get_variable_declarators ()) {
+ var cdecl = new CCodeDeclaration (decl.type_reference.get_cname (false, !decl.type_reference.takes_ownership));
+
+ cdecl.add_declarator ((CCodeVariableDeclarator) decl.ccodenode);
+
+ cfrag.append (cdecl);
+
+ /* try to initialize uninitialized variables */
+ if (decl.initializer == null && decl.type_reference.data_type is Struct) {
+ if (decl.type_reference.data_type.is_reference_type ()) {
+ ((CCodeVariableDeclarator) decl.ccodenode).initializer = new CCodeConstant ("NULL");
+ } else if (decl.type_reference.data_type.get_default_value () != null) {
+ ((CCodeVariableDeclarator) decl.ccodenode).initializer = new CCodeConstant (decl.type_reference.data_type.get_default_value ());
+ } else if (decl.type_reference.data_type is Struct &&
+ struct_has_instance_fields ((Struct) decl.type_reference.data_type)) {
+ var st = (Struct) decl.type_reference.data_type;
+
+ /* memset needs string.h */
+ string_h_needed = true;
+
+ var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
+ czero.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (decl.name)));
+ czero.add_argument (new CCodeConstant ("0"));
+ czero.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (decl.type_reference.get_cname ())));
+
+ cfrag.append (new CCodeExpressionStatement (czero));
+ } else {
+ Report.warning (decl.source_reference, "unable to initialize a variable of type `%s'".printf (decl.type_reference.data_type.symbol.get_full_name ()));
+ }
+ }
+ }
+
+ stmt.ccodenode = cfrag;
+
+ foreach (VariableDeclarator decl in stmt.declaration.get_variable_declarators ()) {
+ if (decl.initializer != null) {
+ create_temp_decl (stmt, decl.initializer.temp_vars);
+ }
+ }
+
+ create_temp_decl (stmt, temp_vars);
+ temp_vars = null;
+ }
+
+ public override void visit_variable_declarator (VariableDeclarator! decl) {
+ if (decl.type_reference.data_type is Array) {
+ // create variables to store array dimensions
+ var arr = (Array) decl.type_reference.data_type;
+
+ for (int dim = 1; dim <= arr.rank; dim++) {
+ var len_decl = new VariableDeclarator (get_array_length_cname (decl.name, dim));
+ len_decl.type_reference = new TypeReference ();
+ len_decl.type_reference.data_type = int_type.data_type;
+
+ temp_vars.prepend (len_decl);
+ }
+ }
+
+ CCodeExpression rhs = null;
+ if (decl.initializer != null) {
+ rhs = (CCodeExpression) decl.initializer.ccodenode;
+
+ if (decl.type_reference.data_type != null
+ && decl.initializer.static_type.data_type != null
+ && decl.type_reference.data_type.is_reference_type ()
+ && decl.initializer.static_type.data_type != decl.type_reference.data_type) {
+ // FIXME: use C cast if debugging disabled
+ rhs = new InstanceCast (rhs, decl.type_reference.data_type);
+ }
+
+ if (decl.type_reference.data_type is Array) {
+ var ccomma = new CCodeCommaExpression ();
+
+ var temp_decl = get_temp_variable_declarator (decl.type_reference);
+ temp_vars.prepend (temp_decl);
+ ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_decl.name), rhs));
+
+ var lhs_array_len = new CCodeIdentifier (get_array_length_cname (decl.name, 1));
+ var rhs_array_len = get_array_length_cexpression (decl.initializer, 1);
+ ccomma.append_expression (new CCodeAssignment (lhs_array_len, rhs_array_len));
+
+ ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
+
+ rhs = ccomma;
+ }
+ } else if (decl.type_reference.data_type != null && decl.type_reference.data_type.is_reference_type ()) {
+ rhs = new CCodeConstant ("NULL");
+ }
+
+ decl.ccodenode = new CCodeVariableDeclarator.with_initializer (decl.name, rhs);
+
+ decl.symbol.active = true;
+ }
+
+ public override void visit_end_initializer_list (InitializerList! list) {
+ if (list.expected_type != null && list.expected_type.data_type is Array) {
+ /* TODO */
+ } else {
+ var clist = new CCodeInitializerList ();
+ foreach (Expression expr in list.get_initializers ()) {
+ clist.append ((CCodeExpression) expr.ccodenode);
+ }
+ list.ccodenode = clist;
+ }
+ }
+
+ private ref VariableDeclarator get_temp_variable_declarator (TypeReference! type, bool takes_ownership = true) {
+ var decl = new VariableDeclarator ("__temp%d".printf (next_temp_var_id));
+ decl.type_reference = type.copy ();
+ decl.type_reference.reference_to_value_type = false;
+ decl.type_reference.is_out = false;
+ decl.type_reference.takes_ownership = takes_ownership;
+
+ next_temp_var_id++;
+
+ return decl;
+ }
+
+ private CCodeExpression get_destroy_func_expression (TypeReference! type) {
+ if (type.data_type != null) {
+ string unref_function;
+ if (type.data_type.is_reference_counting ()) {
+ unref_function = type.data_type.get_unref_function ();
+ } else {
+ unref_function = type.data_type.get_free_function ();
+ }
+ return new CCodeIdentifier (unref_function);
+ } else if (type.type_parameter != null && current_class != null) {
+ string func_name = "%s_destroy_func".printf (type.type_parameter.name.down ());
+ return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
+ } else {
+ return new CCodeConstant ("NULL");
+ }
+ }
+
+ private ref CCodeExpression get_unref_expression (CCodeExpression! cvar, TypeReference! type) {
+ /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
+
+ /* can be simplified to
+ * foo = (unref (foo), NULL)
+ * if foo is of static type non-null
+ */
+
+ if (type.is_null) {
+ return new CCodeConstant ("NULL");
+ }
+
+ var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cvar, new CCodeConstant ("NULL"));
+ if (type.data_type == null) {
+ if (current_class == null) {
+ return new CCodeConstant ("NULL");
+ }
+
+ // unref functions are optional for type parameters
+ var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL"));
+ cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull);
+ }
+
+ var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
+ ccall.add_argument (cvar);
+
+ /* set freed references to NULL to prevent further use */
+ var ccomma = new CCodeCommaExpression ();
+
+ // TODO cleanup
+ if (type.data_type != null && !type.data_type.is_reference_counting ()) {
+ string unref_function = type.data_type.get_free_function ();
+ if (unref_function == "g_list_free") {
+ bool is_ref = false;
+ bool is_class = false;
+ bool is_interface = false;
+
+ foreach (TypeReference type_arg in type.get_type_arguments ()) {
+ is_ref |= type_arg.takes_ownership;
+ is_class |= type_arg.data_type is Class;
+ is_interface |= type_arg.data_type is Interface;
+ }
+
+ if (is_ref) {
+ var cunrefcall = new CCodeFunctionCall (new CCodeIdentifier ("g_list_foreach"));
+ cunrefcall.add_argument (cvar);
+ if (is_class || is_interface) {
+ cunrefcall.add_argument (new CCodeIdentifier ("(GFunc) g_object_unref"));
+ } else {
+ cunrefcall.add_argument (new CCodeIdentifier ("(GFunc) g_free"));
+ }
+ cunrefcall.add_argument (new CCodeConstant ("NULL"));
+ ccomma.append_expression (cunrefcall);
+ }
+ } else if (unref_function == "g_string_free") {
+ ccall.add_argument (new CCodeConstant ("TRUE"));
+ }
+ }
+
+ ccomma.append_expression (ccall);
+ ccomma.append_expression (new CCodeConstant ("NULL"));
+
+ var cassign = new CCodeAssignment (cvar, ccomma);
+
+ // g_free (NULL) is allowed
+ if (type.non_null || (type.data_type != null && !type.data_type.is_reference_counting () && type.data_type.get_free_function () == "g_free")) {
+ return new CCodeParenthesizedExpression (cassign);
+ }
+
+ return new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), new CCodeParenthesizedExpression (cassign));
+ }
+
+ public override void visit_end_full_expression (Expression! expr) {
+ if (!memory_management) {
+ temp_vars = null;
+ temp_ref_vars = null;
+ return;
+ }
+
+ /* expr is a full expression, i.e. an initializer, the
+ * expression in an expression statement, the controlling
+ * expression in if, while, for, or foreach statements
+ *
+ * we unref temporary variables at the end of a full
+ * expression
+ */
+
+ /* can't automatically deep copy lists yet, so do it
+ * manually for now
+ * replace with
+ * expr.temp_vars = temp_vars;
+ * when deep list copying works
+ */
+ expr.temp_vars = null;
+ foreach (VariableDeclarator decl1 in temp_vars) {
+ expr.temp_vars.append (decl1);
+ }
+ temp_vars = null;
+
+ if (temp_ref_vars == null) {
+ /* nothing to do without temporary variables */
+ return;
+ }
+
+ var full_expr_decl = get_temp_variable_declarator (expr.static_type);
+ expr.temp_vars.append (full_expr_decl);
+
+ var expr_list = new CCodeCommaExpression ();
+ expr_list.append_expression (new CCodeAssignment (new CCodeIdentifier (full_expr_decl.name), (CCodeExpression) expr.ccodenode));
+
+ foreach (VariableDeclarator decl in temp_ref_vars) {
+ expr_list.append_expression (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference));
+ }
+
+ expr_list.append_expression (new CCodeIdentifier (full_expr_decl.name));
+
+ expr.ccodenode = expr_list;
+
+ temp_ref_vars = null;
+ }
+
+ private void append_temp_decl (CCodeFragment! cfrag, List<VariableDeclarator> temp_vars) {
+ foreach (VariableDeclarator decl in temp_vars) {
+ var cdecl = new CCodeDeclaration (decl.type_reference.get_cname (true, !decl.type_reference.takes_ownership));
+
+ var vardecl = new CCodeVariableDeclarator (decl.name);
+ cdecl.add_declarator (vardecl);
+
+ if (decl.type_reference.data_type != null && decl.type_reference.data_type.is_reference_type ()) {
+ vardecl.initializer = new CCodeConstant ("NULL");
+ }
+
+ cfrag.append (cdecl);
+ }
+ }
+
+ public override void visit_expression_statement (ExpressionStatement! stmt) {
+ stmt.ccodenode = new CCodeExpressionStatement ((CCodeExpression) stmt.expression.ccodenode);
+
+ /* free temporary objects */
+ if (!memory_management) {
+ temp_vars = null;
+ temp_ref_vars = null;
+ return;
+ }
+
+ if (temp_vars == null) {
+ /* nothing to do without temporary variables */
+ return;
+ }
+
+ var cfrag = new CCodeFragment ();
+ append_temp_decl (cfrag, temp_vars);
+
+ cfrag.append (stmt.ccodenode);
+
+ foreach (VariableDeclarator decl in temp_ref_vars) {
+ cfrag.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference)));
+ }
+
+ stmt.ccodenode = cfrag;
+
+ temp_vars = null;
+ temp_ref_vars = null;
+ }
+
+ private void create_temp_decl (Statement! stmt, List<VariableDeclarator> temp_vars) {
+ /* declare temporary variables */
+
+ if (temp_vars == null) {
+ /* nothing to do without temporary variables */
+ return;
+ }
+
+ var cfrag = new CCodeFragment ();
+ append_temp_decl (cfrag, temp_vars);
+
+ cfrag.append (stmt.ccodenode);
+
+ stmt.ccodenode = cfrag;
+ }
+
+ public override void visit_if_statement (IfStatement! stmt) {
+ if (stmt.false_statement != null) {
+ stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode, (CCodeStatement) stmt.false_statement.ccodenode);
+ } else {
+ stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode);
+ }
+
+ create_temp_decl (stmt, stmt.condition.temp_vars);
+ }
+
+ public override void visit_switch_statement (SwitchStatement! stmt) {
+ // we need a temporary variable to save the property value
+ var temp_decl = get_temp_variable_declarator (stmt.expression.static_type);
+ stmt.expression.temp_vars.prepend (temp_decl);
+
+ var ctemp = new CCodeIdentifier (temp_decl.name);
+
+ var cinit = new CCodeAssignment (ctemp, (CCodeExpression) stmt.expression.ccodenode);
+
+ var cswitchblock = new CCodeFragment ();
+ cswitchblock.append (new CCodeExpressionStatement (cinit));
+ stmt.ccodenode = cswitchblock;
+
+ create_temp_decl (stmt, stmt.expression.temp_vars);
+
+ List<weak Statement> default_statements = null;
+
+ // generate nested if statements
+ ref CCodeStatement ctopstmt = null;
+ CCodeIfStatement coldif = null;
+ foreach (SwitchSection section in stmt.get_sections ()) {
+ if (section.has_default_label ()) {
+ default_statements = section.get_statements ();
+ } else {
+ CCodeBinaryExpression cor = null;
+ foreach (SwitchLabel label in section.get_labels ()) {
+ var ccmp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, (CCodeExpression) label.expression.ccodenode);
+ if (cor == null) {
+ cor = ccmp;
+ } else {
+ cor = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cor, ccmp);
+ }
+ }
+
+ var cblock = new CCodeBlock ();
+ foreach (Statement body_stmt in section.get_statements ()) {
+ if (body_stmt.ccodenode is CCodeFragment) {
+ foreach (CCodeStatement cstmt in ((CCodeFragment) body_stmt.ccodenode).get_children ()) {
+ cblock.add_statement (cstmt);
+ }
+ } else {
+ cblock.add_statement ((CCodeStatement) body_stmt.ccodenode);
+ }
+ }
+
+ var cdo = new CCodeDoStatement (cblock, new CCodeConstant ("0"));
+
+ var cif = new CCodeIfStatement (cor, cdo);
+ if (coldif != null) {
+ coldif.false_statement = cif;
+ } else {
+ ctopstmt = cif;
+ }
+ coldif = cif;
+ }
+ }
+
+ if (default_statements != null) {
+ var cblock = new CCodeBlock ();
+ foreach (Statement body_stmt in default_statements) {
+ cblock.add_statement ((CCodeStatement) body_stmt.ccodenode);
+ }
+
+ var cdo = new CCodeDoStatement (cblock, new CCodeConstant ("0"));
+
+ if (coldif == null) {
+ // there is only one section and that section
+ // contains a default label
+ ctopstmt = cdo;
+ } else {
+ coldif.false_statement = cdo;
+ }
+ }
+
+ cswitchblock.append (ctopstmt);
+ }
+
+ public override void visit_while_statement (WhileStatement! stmt) {
+ stmt.ccodenode = new CCodeWhileStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.body.ccodenode);
+
+ create_temp_decl (stmt, stmt.condition.temp_vars);
+ }
+
+ public override void visit_do_statement (DoStatement! stmt) {
+ stmt.ccodenode = new CCodeDoStatement ((CCodeStatement) stmt.body.ccodenode, (CCodeExpression) stmt.condition.ccodenode);
+
+ create_temp_decl (stmt, stmt.condition.temp_vars);
+ }
+
+ public override void visit_for_statement (ForStatement! stmt) {
+ var cfor = new CCodeForStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.body.ccodenode);
+ stmt.ccodenode = cfor;
+
+ foreach (Expression init_expr in stmt.get_initializer ()) {
+ cfor.add_initializer ((CCodeExpression) init_expr.ccodenode);
+ create_temp_decl (stmt, init_expr.temp_vars);
+ }
+
+ foreach (Expression it_expr in stmt.get_iterator ()) {
+ cfor.add_iterator ((CCodeExpression) it_expr.ccodenode);
+ create_temp_decl (stmt, it_expr.temp_vars);
+ }
+
+ create_temp_decl (stmt, stmt.condition.temp_vars);
+ }
+
+ public override void visit_end_foreach_statement (ForeachStatement! stmt) {
+ var cblock = new CCodeBlock ();
+ CCodeForStatement cfor;
+ VariableDeclarator collection_backup = get_temp_variable_declarator (stmt.collection.static_type);
+
+ stmt.collection.temp_vars.prepend (collection_backup);
+ var cfrag = new CCodeFragment ();
+ append_temp_decl (cfrag, stmt.collection.temp_vars);
+ cblock.add_statement (cfrag);
+ cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (collection_backup.name), (CCodeExpression) stmt.collection.ccodenode)));
+
+ stmt.ccodenode = cblock;
+
+ if (stmt.collection.static_type.data_type is Array) {
+ var arr = (Array) stmt.collection.static_type.data_type;
+
+ var array_len = get_array_length_cexpression (stmt.collection, 1);
+
+ /* the array has no length parameter i.e. is NULL-terminated array */
+ if (array_len is CCodeConstant) {
+ var it_name = "%s_it".printf (stmt.variable_name);
+
+ var citdecl = new CCodeDeclaration (stmt.collection.static_type.get_cname ());
+ citdecl.add_declarator (new CCodeVariableDeclarator (it_name));
+ cblock.add_statement (citdecl);
+
+ var cbody = new CCodeBlock ();
+
+ var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, new CCodeIdentifier ("*%s".printf (it_name))));
+ cbody.add_statement (cdecl);
+
+ cbody.add_statement (stmt.body.ccodenode);
+
+ var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("*%s".printf (it_name)), new CCodeConstant ("NULL"));
+
+ var cfor = new CCodeForStatement (ccond, cbody);
+
+ cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeIdentifier (collection_backup.name)));
+
+ cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (it_name), new CCodeConstant ("1"))));
+ cblock.add_statement (cfor);
+ /* the array has a length parameter */
+ } else {
+ var it_name = (stmt.variable_name + "_it");
+
+ var citdecl = new CCodeDeclaration ("int");
+ citdecl.add_declarator (new CCodeVariableDeclarator (it_name));
+ cblock.add_statement (citdecl);
+
+ var cbody = new CCodeBlock ();
+
+ var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, new CCodeElementAccess (new CCodeIdentifier (collection_backup.name), new CCodeIdentifier (it_name))));
+ cbody.add_statement (cdecl);
+
+ cbody.add_statement (stmt.body.ccodenode);
+
+ var ccond_ind1 = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, array_len, new CCodeConstant ("-1"));
+ var ccond_ind2 = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier (it_name), array_len);
+ var ccond_ind = new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccond_ind1, ccond_ind2);
+
+ /* only check for null if the containers elements are of reference-type */
+ CCodeBinaryExpression ccond;
+ if (arr.element_type.is_reference_type ()) {
+ var ccond_term1 = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, array_len, new CCodeConstant ("-1"));
+ var ccond_term2 = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeElementAccess (new CCodeIdentifier (collection_backup.name), new CCodeIdentifier (it_name)), new CCodeConstant ("NULL"));
+ var ccond_term = new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccond_term1, ccond_term2);
+
+ ccond = new CCodeBinaryExpression (CCodeBinaryOperator.OR, new CCodeParenthesizedExpression (ccond_ind), new CCodeParenthesizedExpression (ccond_term));
+ } else {
+ ccond = ccond_ind;
+ }
+
+ var cfor = new CCodeForStatement (ccond, cbody);
+ cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeConstant ("0")));
+ cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (it_name), new CCodeConstant ("1"))));
+ cblock.add_statement (cfor);
+ }
+ } else if (stmt.collection.static_type.data_type == list_type ||
+ stmt.collection.static_type.data_type == slist_type) {
+ var it_name = "%s_it".printf (stmt.variable_name);
+
+ var citdecl = new CCodeDeclaration (stmt.collection.static_type.get_cname ());
+ citdecl.add_declarator (new CCodeVariableDeclarator (it_name));
+ cblock.add_statement (citdecl);
+
+ var cbody = new CCodeBlock ();
+
+ CCodeExpression element_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier (it_name), "data");
+
+ /* cast pointer to actual type if appropriate */
+ if (stmt.type_reference.data_type is Struct) {
+ var st = (Struct) stmt.type_reference.data_type;
+ if (st == uint_type.data_type) {
+ var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_UINT"));
+ cconv.add_argument (element_expr);
+ element_expr = cconv;
+ } else if (st == bool_type.data_type || st.is_integer_type ()) {
+ var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_INT"));
+ cconv.add_argument (element_expr);
+ element_expr = cconv;
+ }
+ }
+
+ var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr));
+ cbody.add_statement (cdecl);
+
+ cbody.add_statement (stmt.body.ccodenode);
+
+ var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier (it_name), new CCodeConstant ("NULL"));
+
+ var cfor = new CCodeForStatement (ccond, cbody);
+
+ cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeIdentifier (collection_backup.name)));
+
+ cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeMemberAccess.pointer (new CCodeIdentifier (it_name), "next")));
+ cblock.add_statement (cfor);
+ }
+
+ if (memory_management && stmt.collection.static_type.transfers_ownership) {
+ cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (collection_backup.name), stmt.collection.static_type)));
+ }
+ }
+
+ public override void visit_break_statement (BreakStatement! stmt) {
+ stmt.ccodenode = new CCodeBreakStatement ();
+ }
+
+ public override void visit_continue_statement (ContinueStatement! stmt) {
+ stmt.ccodenode = new CCodeContinueStatement ();
+ }
+
+ private void append_local_free (Symbol sym, CCodeFragment cfrag, bool stop_at_loop) {
+ var b = (Block) sym.node;
+
+ var local_vars = b.get_local_variables ();
+ foreach (VariableDeclarator decl in local_vars) {
+ if (decl.symbol.active && decl.type_reference.data_type.is_reference_type () && decl.type_reference.takes_ownership) {
+ cfrag.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference)));
+ }
+ }
+
+ if (sym.parent_symbol.node is Block) {
+ append_local_free (sym.parent_symbol, cfrag, stop_at_loop);
+ }
+ }
+
+ private void create_local_free (Statement stmt) {
+ if (!memory_management) {
+ return;
+ }
+
+ var cfrag = new CCodeFragment ();
+
+ append_local_free (current_symbol, cfrag, false);
+
+ cfrag.append (stmt.ccodenode);
+ stmt.ccodenode = cfrag;
+ }
+
+ private bool append_local_free_expr (Symbol sym, CCodeCommaExpression ccomma, bool stop_at_loop) {
+ var found = false;
+
+ var b = (Block) sym.node;
+
+ var local_vars = b.get_local_variables ();
+ foreach (VariableDeclarator decl in local_vars) {
+ if (decl.symbol.active && decl.type_reference.data_type.is_reference_type () && decl.type_reference.takes_ownership) {
+ found = true;
+ ccomma.append_expression (get_unref_expression (new CCodeIdentifier (decl.name), decl.type_reference));
+ }
+ }
+
+ if (sym.parent_symbol.node is Block) {
+ found = found || append_local_free_expr (sym.parent_symbol, ccomma, stop_at_loop);
+ }
+
+ return found;
+ }
+
+ private void create_local_free_expr (Expression expr) {
+ if (!memory_management) {
+ return;
+ }
+
+ var return_expr_decl = get_temp_variable_declarator (expr.static_type);
+
+ var ccomma = new CCodeCommaExpression ();
+ ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (return_expr_decl.name), (CCodeExpression) expr.ccodenode));
+
+ if (!append_local_free_expr (current_symbol, ccomma, false)) {
+ /* no local variables need to be freed */
+ return;
+ }
+
+ ccomma.append_expression (new CCodeIdentifier (return_expr_decl.name));
+
+ expr.ccodenode = ccomma;
+ expr.temp_vars.append (return_expr_decl);
+ }
+
+ public override void visit_begin_return_statement (ReturnStatement! stmt) {
+ if (stmt.return_expression != null) {
+ // avoid unnecessary ref/unref pair
+ if (stmt.return_expression.ref_missing &&
+ stmt.return_expression.symbol_reference != null &&
+ stmt.return_expression.symbol_reference.node is VariableDeclarator) {
+ var decl = (VariableDeclarator) stmt.return_expression.symbol_reference.node;
+ if (decl.type_reference.takes_ownership) {
+ /* return expression is local variable taking ownership and
+ * current method is transferring ownership */
+
+ stmt.return_expression.ref_sink = true;
+
+ // don't ref expression
+ stmt.return_expression.ref_missing = false;
+ }
+ }
+ }
+ }
+
+ public override void visit_end_return_statement (ReturnStatement! stmt) {
+ if (stmt.return_expression == null) {
+ stmt.ccodenode = new CCodeReturnStatement ();
+
+ create_local_free (stmt);
+ } else {
+ Symbol return_expression_symbol = null;
+
+ // avoid unnecessary ref/unref pair
+ if (stmt.return_expression.ref_sink &&
+ stmt.return_expression.symbol_reference != null &&
+ stmt.return_expression.symbol_reference.node is VariableDeclarator) {
+ var decl = (VariableDeclarator) stmt.return_expression.symbol_reference.node;
+ if (decl.type_reference.takes_ownership) {
+ /* return expression is local variable taking ownership and
+ * current method is transferring ownership */
+
+ // don't unref expression
+ return_expression_symbol = decl.symbol;
+ return_expression_symbol.active = false;
+ }
+ }
+
+ create_local_free_expr (stmt.return_expression);
+
+ if (stmt.return_expression.static_type != null &&
+ stmt.return_expression.static_type.data_type != current_return_type.data_type) {
+ /* cast required */
+ if (current_return_type.data_type is Class || current_return_type.data_type is Interface) {
+ stmt.return_expression.ccodenode = new InstanceCast ((CCodeExpression) stmt.return_expression.ccodenode, current_return_type.data_type);
+ }
+ }
+
+ stmt.ccodenode = new CCodeReturnStatement ((CCodeExpression) stmt.return_expression.ccodenode);
+
+ create_temp_decl (stmt, stmt.return_expression.temp_vars);
+
+ if (return_expression_symbol != null) {
+ return_expression_symbol.active = true;
+ }
+ }
+ }
+
+ private ref string get_symbol_lock_name (Symbol! sym) {
+ return "__lock_%s".printf (sym.name);
+ }
+
+ /**
+ * Visit operation called for lock statements.
+ *
+ * @param stmt a lock statement
+ */
+ public override void visit_lock_statement (LockStatement! stmt) {
+ var cn = new CCodeFragment ();
+ CCodeExpression l = null;
+ CCodeFunctionCall fc;
+ var inner_node = ((MemberAccess)stmt.resource).inner;
+
+ if (inner_node == null) {
+ l = new CCodeIdentifier ("self");
+ } else if (stmt.resource.symbol_reference.parent_symbol.node != current_class) {
+ l = new CCodeFunctionCall (new CCodeIdentifier (((DataType) stmt.resource.symbol_reference.parent_symbol.node).get_upper_case_cname ()));
+ ((CCodeFunctionCall) l).add_argument ((CCodeExpression)inner_node.ccodenode);
+ } else {
+ l = (CCodeExpression)inner_node.ccodenode;
+ }
+ l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (stmt.resource.symbol_reference));
+
+ fc = new CCodeFunctionCall (new CCodeIdentifier (((Method)mutex_type.data_type.symbol.lookup ("lock").node).get_cname ()));
+ fc.add_argument (l);
+ cn.append (new CCodeExpressionStatement (fc));
+
+ cn.append (stmt.body.ccodenode);
+
+ fc = new CCodeFunctionCall (new CCodeIdentifier (((Method)mutex_type.data_type.symbol.lookup ("unlock").node).get_cname ()));
+ fc.add_argument (l);
+ cn.append (new CCodeExpressionStatement (fc));
+
+ stmt.ccodenode = cn;
+ }
+
+ /**
+ * Visit operations called for array creation expresions.
+ *
+ * @param expr an array creation expression
+ */
+ public override void visit_end_array_creation_expression (ArrayCreationExpression! expr) {
+ /* FIXME: rank > 1 not supported yet */
+ if (expr.rank > 1) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Creating arrays with rank greater than 1 is not supported yet");
+ }
+
+ var sizes = expr.get_sizes ();
+ var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
+ gnew.add_argument (new CCodeIdentifier (expr.element_type.get_cname ()));
+ /* FIXME: had to add Expression cast due to possible compiler bug */
+ gnew.add_argument ((CCodeExpression) ((Expression) sizes.first ().data).ccodenode);
+
+ if (expr.initializer_list != null) {
+ var ce = new CCodeCommaExpression ();
+ var temp_var = get_temp_variable_declarator (expr.static_type);
+ var name_cnode = new CCodeIdentifier (temp_var.name);
+ int i = 0;
+
+ temp_vars.prepend (temp_var);
+
+ /* FIXME: had to add Expression cast due to possible compiler bug */
+ ce.append_expression (new CCodeAssignment (name_cnode, gnew));
+
+ foreach (Expression e in expr.initializer_list.get_initializers ()) {
+ ce.append_expression (new CCodeAssignment (new CCodeElementAccess (name_cnode, new CCodeConstant (i.to_string ())), (CCodeExpression) e.ccodenode));
+ i++;
+ }
+
+ ce.append_expression (name_cnode);
+
+ expr.ccodenode = ce;
+ } else {
+ expr.ccodenode = gnew;
+ }
+ }
+
+ public override void visit_boolean_literal (BooleanLiteral! expr) {
+ expr.ccodenode = new CCodeConstant (expr.value ? "TRUE" : "FALSE");
+ }
+
+ public override void visit_character_literal (CharacterLiteral! expr) {
+ if (expr.get_char () >= 0x20 && expr.get_char () < 0x80) {
+ expr.ccodenode = new CCodeConstant (expr.value);
+ } else {
+ expr.ccodenode = new CCodeConstant ("%uU".printf (expr.get_char ()));
+ }
+ }
+
+ public override void visit_integer_literal (IntegerLiteral! expr) {
+ expr.ccodenode = new CCodeConstant (expr.value);
+ }
+
+ public override void visit_real_literal (RealLiteral! expr) {
+ expr.ccodenode = new CCodeConstant (expr.value);
+ }
+
+ public override void visit_string_literal (StringLiteral! expr) {
+ expr.ccodenode = new CCodeConstant (expr.value);
+ }
+
+ public override void visit_null_literal (NullLiteral! expr) {
+ expr.ccodenode = new CCodeConstant ("NULL");
+ }
+
+ public override void visit_literal_expression (LiteralExpression! expr) {
+ expr.ccodenode = expr.literal.ccodenode;
+
+ visit_expression (expr);
+ }
+
+ private void process_cmember (MemberAccess! expr, CCodeExpression pub_inst, DataType base_type) {
+ if (expr.symbol_reference.node is Method) {
+ var m = (Method) expr.symbol_reference.node;
+
+ if (expr.inner is BaseAccess) {
+ if (m.base_interface_method != null) {
+ var base_iface = (Interface) m.base_interface_method.symbol.parent_symbol.node;
+ string parent_iface_var = "%s_%s_parent_iface".printf (current_class.get_lower_case_cname (null), base_iface.get_lower_case_cname (null));
+
+ expr.ccodenode = new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), m.name);
+ return;
+ } else if (m.base_method != null) {
+ var base_class = (Class) m.base_method.symbol.parent_symbol.node;
+ var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null))));
+ vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null))));
+
+ expr.ccodenode = new CCodeMemberAccess.pointer (vcast, m.name);
+ return;
+ }
+ }
+
+ if (m.base_interface_method != null) {
+ expr.ccodenode = new CCodeIdentifier (m.base_interface_method.get_cname ());
+ } else if (m.base_method != null) {
+ expr.ccodenode = new CCodeIdentifier (m.base_method.get_cname ());
+ } else {
+ expr.ccodenode = new CCodeIdentifier (m.get_cname ());
+ }
+ } else if (expr.symbol_reference.node is ArrayLengthField) {
+ expr.ccodenode = get_array_length_cexpression (expr.inner, 1);
+ } else if (expr.symbol_reference.node is Field) {
+ var f = (Field) expr.symbol_reference.node;
+ if (f.instance) {
+ ref CCodeExpression typed_inst;
+ if (f.symbol.parent_symbol.node != base_type) {
+ // FIXME: use C cast if debugging disabled
+ typed_inst = new CCodeFunctionCall (new CCodeIdentifier (((DataType) f.symbol.parent_symbol.node).get_upper_case_cname (null)));
+ ((CCodeFunctionCall) typed_inst).add_argument (pub_inst);
+ } else {
+ typed_inst = pub_inst;
+ }
+ ref CCodeExpression inst;
+ if (f.access == MemberAccessibility.PRIVATE) {
+ inst = new CCodeMemberAccess.pointer (typed_inst, "priv");
+ } else {
+ inst = typed_inst;
+ }
+ if (((DataType) f.symbol.parent_symbol.node).is_reference_type ()) {
+ expr.ccodenode = new CCodeMemberAccess.pointer (inst, f.get_cname ());
+ } else {
+ expr.ccodenode = new CCodeMemberAccess (inst, f.get_cname ());
+ }
+ } else {
+ expr.ccodenode = new CCodeIdentifier (f.get_cname ());
+ }
+ } else if (expr.symbol_reference.node is Constant) {
+ var c = (Constant) expr.symbol_reference.node;
+ expr.ccodenode = new CCodeIdentifier (c.get_cname ());
+ } else if (expr.symbol_reference.node is Property) {
+ var prop = (Property) expr.symbol_reference.node;
+
+ if (!prop.no_accessor_method) {
+ var base_property = prop;
+ if (prop.base_property != null) {
+ base_property = prop.base_property;
+ } else if (prop.base_interface_property != null) {
+ base_property = prop.base_interface_property;
+ }
+ var base_property_type = (DataType) base_property.symbol.parent_symbol.node;
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_get_%s".printf (base_property_type.get_lower_case_cname (null), base_property.name)));
+
+ /* explicitly use strong reference as ccast
+ * gets unrefed at the end of the inner block
+ */
+ ref CCodeExpression typed_pub_inst = pub_inst;
+
+ /* cast if necessary */
+ if (base_property_type != base_type) {
+ // FIXME: use C cast if debugging disabled
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier (base_property_type.get_upper_case_cname (null)));
+ ccast.add_argument (pub_inst);
+ typed_pub_inst = ccast;
+ }
+
+ ccall.add_argument (typed_pub_inst);
+ expr.ccodenode = ccall;
+ } else {
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
+
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
+ ccast.add_argument (pub_inst);
+ ccall.add_argument (ccast);
+
+ // property name is second argument of g_object_get
+ ccall.add_argument (prop.get_canonical_cconstant ());
+
+
+ // we need a temporary variable to save the property value
+ var temp_decl = get_temp_variable_declarator (expr.static_type);
+ temp_vars.prepend (temp_decl);
+
+ var ctemp = new CCodeIdentifier (temp_decl.name);
+ ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
+
+
+ ccall.add_argument (new CCodeConstant ("NULL"));
+
+ var ccomma = new CCodeCommaExpression ();
+ ccomma.append_expression (ccall);
+ ccomma.append_expression (ctemp);
+ expr.ccodenode = ccomma;
+ }
+ } else if (expr.symbol_reference.node is EnumValue) {
+ var ev = (EnumValue) expr.symbol_reference.node;
+ expr.ccodenode = new CCodeConstant (ev.get_cname ());
+ } else if (expr.symbol_reference.node is VariableDeclarator) {
+ var decl = (VariableDeclarator) expr.symbol_reference.node;
+ expr.ccodenode = new CCodeIdentifier (decl.name);
+ } else if (expr.symbol_reference.node is FormalParameter) {
+ var p = (FormalParameter) expr.symbol_reference.node;
+ if (p.name == "this") {
+ expr.ccodenode = pub_inst;
+ } else {
+ if (p.type_reference.is_out || p.type_reference.reference_to_value_type) {
+ expr.ccodenode = new CCodeIdentifier ("(*%s)".printf (p.name));
+ } else {
+ expr.ccodenode = new CCodeIdentifier (p.name);
+ }
+ }
+ } else if (expr.symbol_reference.node is Signal) {
+ var sig = (Signal) expr.symbol_reference.node;
+ var cl = (DataType) sig.symbol.parent_symbol.node;
+
+ if (sig.has_emitter) {
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_%s".printf (cl.get_lower_case_cname (null), sig.name)));
+
+ /* explicitly use strong reference as ccast
+ * gets unrefed at the end of the inner block
+ */
+ ref CCodeExpression typed_pub_inst = pub_inst;
+
+ /* cast if necessary */
+ if (cl != base_type) {
+ // FIXME: use C cast if debugging disabled
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null)));
+ ccast.add_argument (pub_inst);
+ typed_pub_inst = ccast;
+ }
+
+ ccall.add_argument (typed_pub_inst);
+ expr.ccodenode = ccall;
+ } else {
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
+
+ // FIXME: use C cast if debugging disabled
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
+ ccast.add_argument (pub_inst);
+ ccall.add_argument (ccast);
+
+ ccall.add_argument (sig.get_canonical_cconstant ());
+
+ expr.ccodenode = ccall;
+ }
+ }
+ }
+
+ public override void visit_parenthesized_expression (ParenthesizedExpression! expr) {
+ expr.ccodenode = new CCodeParenthesizedExpression ((CCodeExpression) expr.inner.ccodenode);
+
+ visit_expression (expr);
+ }
+
+ public override void visit_member_access (MemberAccess! expr) {
+ CCodeExpression pub_inst = null;
+ DataType base_type = null;
+
+ if (expr.inner == null) {
+ pub_inst = new CCodeIdentifier ("self");
+
+ if (current_type_symbol != null) {
+ /* base type is available if this is a type method */
+ base_type = (DataType) current_type_symbol.node;
+
+ if (!base_type.is_reference_type ()) {
+ pub_inst = new CCodeIdentifier ("(*self)");
+ }
+ }
+ } else {
+ pub_inst = (CCodeExpression) expr.inner.ccodenode;
+
+ if (expr.inner.static_type != null) {
+ base_type = expr.inner.static_type.data_type;
+ }
+ }
+
+ process_cmember (expr, pub_inst, base_type);
+
+ visit_expression (expr);
+ }
+
+ private ref CCodeExpression! get_array_length_cexpression (Expression! array_expr, int dim) {
+ bool is_out = false;
+
+ if (array_expr is UnaryExpression) {
+ var unary_expr = (UnaryExpression) array_expr;
+ if (unary_expr.operator == UnaryOperator.OUT) {
+ array_expr = unary_expr.inner;
+ is_out = true;
+ }
+ }
+
+ if (array_expr is ArrayCreationExpression) {
+ var size = ((ArrayCreationExpression) array_expr).get_sizes ();
+ var length_expr = (Expression) size.nth_data (dim - 1);
+ return (CCodeExpression) length_expr.ccodenode;
+ } else if (array_expr.symbol_reference != null) {
+ if (array_expr.symbol_reference.node is FormalParameter) {
+ var param = (FormalParameter) array_expr.symbol_reference.node;
+ if (!param.no_array_length) {
+ var length_expr = new CCodeIdentifier (get_array_length_cname (param.name, dim));
+ if (is_out) {
+ return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
+ } else {
+ return length_expr;
+ }
+ }
+ } else if (array_expr.symbol_reference.node is VariableDeclarator) {
+ var decl = (VariableDeclarator) array_expr.symbol_reference.node;
+ var length_expr = new CCodeIdentifier (get_array_length_cname (decl.name, dim));
+ if (is_out) {
+ return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
+ } else {
+ return length_expr;
+ }
+ } else if (array_expr.symbol_reference.node is Field) {
+ var field = (Field) array_expr.symbol_reference.node;
+ if (!field.no_array_length) {
+ var length_cname = get_array_length_cname (field.name, dim);
+
+ var ma = (MemberAccess) array_expr;
+
+ CCodeExpression pub_inst = null;
+ DataType base_type = null;
+ CCodeExpression length_expr = null;
+
+ if (ma.inner == null) {
+ pub_inst = new CCodeIdentifier ("self");
+
+ if (current_type_symbol != null) {
+ /* base type is available if this is a type method */
+ base_type = (DataType) current_type_symbol.node;
+ }
+ } else {
+ pub_inst = (CCodeExpression) ma.inner.ccodenode;
+
+ if (ma.inner.static_type != null) {
+ base_type = ma.inner.static_type.data_type;
+ }
+ }
+
+ if (field.instance) {
+ ref CCodeExpression typed_inst;
+ if (field.symbol.parent_symbol.node != base_type) {
+ // FIXME: use C cast if debugging disabled
+ typed_inst = new CCodeFunctionCall (new CCodeIdentifier (((DataType) field.symbol.parent_symbol.node).get_upper_case_cname (null)));
+ ((CCodeFunctionCall) typed_inst).add_argument (pub_inst);
+ } else {
+ typed_inst = pub_inst;
+ }
+ ref CCodeExpression inst;
+ if (field.access == MemberAccessibility.PRIVATE) {
+ inst = new CCodeMemberAccess.pointer (typed_inst, "priv");
+ } else {
+ inst = typed_inst;
+ }
+ if (((DataType) field.symbol.parent_symbol.node).is_reference_type ()) {
+ length_expr = new CCodeMemberAccess.pointer (inst, length_cname);
+ } else {
+ length_expr = new CCodeMemberAccess (inst, length_cname);
+ }
+ } else {
+ length_expr = new CCodeIdentifier (length_cname);
+ }
+
+ if (is_out) {
+ return new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr);
+ } else {
+ return length_expr;
+ }
+ }
+ }
+ }
+
+ /* if we reach this point we were not able to get the explicit length of the array
+ * this is not allowed for an array of non-reference-type structs
+ */
+ if (((Array)array_expr.static_type.data_type).element_type is Struct) {
+ var s = (Struct)((Array)array_expr.static_type.data_type).element_type;
+ if (!s.is_reference_type ()) {
+ array_expr.error = true;
+ Report.error (array_expr.source_reference, "arrays of value-type structs with no explicit length parameter are not supported");
+ }
+ }
+
+ if (!is_out) {
+ return new CCodeConstant ("-1");
+ } else {
+ return new CCodeConstant ("NULL");
+ }
+ }
+
+ public override void visit_end_invocation_expression (InvocationExpression! expr) {
+ var ccall = new CCodeFunctionCall ((CCodeExpression) expr.call.ccodenode);
+
+ Method m = null;
+ List<weak FormalParameter> params;
+
+ if (!(expr.call is MemberAccess)) {
+ expr.error = true;
+ Report.error (expr.source_reference, "unsupported method invocation");
+ return;
+ }
+
+ var ma = (MemberAccess) expr.call;
+
+ if (expr.call.symbol_reference.node is Invokable) {
+ var i = (Invokable) expr.call.symbol_reference.node;
+ params = i.get_parameters ();
+
+ if (i is Method) {
+ m = (Method) i;
+ } else if (i is Signal) {
+ ccall = (CCodeFunctionCall) expr.call.ccodenode;
+ }
+ }
+
+ if (m is ArrayResizeMethod) {
+ var array = (Array) m.symbol.parent_symbol.node;
+ ccall.add_argument (new CCodeIdentifier (array.get_cname ()));
+ }
+
+ /* explicitly use strong reference as ccall gets unrefed
+ * at end of inner block
+ */
+ ref CCodeExpression instance;
+ if (m != null && m.instance) {
+ var base_method = m;
+ if (m.base_interface_method != null) {
+ base_method = m.base_interface_method;
+ } else if (m.base_method != null) {
+ base_method = m.base_method;
+ }
+
+ var req_cast = false;
+ if (ma.inner == null) {
+ instance = new CCodeIdentifier ("self");
+ /* require casts for overriden and inherited methods */
+ req_cast = m.overrides || m.base_interface_method != null || (m.symbol.parent_symbol != current_type_symbol);
+ } else {
+ instance = (CCodeExpression) ma.inner.ccodenode;
+ /* reqiure casts if the type of the used instance is
+ * different than the type which declared the method */
+ req_cast = base_method.symbol.parent_symbol.node != ma.inner.static_type.data_type;
+ }
+
+ if (m.instance_by_reference && (ma.inner != null || m.symbol.parent_symbol != current_type_symbol)) {
+ instance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance);
+ }
+
+ if (req_cast && ((DataType) m.symbol.parent_symbol.node).is_reference_type ()) {
+ // FIXME: use C cast if debugging disabled
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (((DataType) base_method.symbol.parent_symbol.node).get_upper_case_cname (null)));
+ ccall.add_argument (instance);
+ instance = ccall;
+ }
+
+ if (!m.instance_last) {
+ ccall.add_argument (instance);
+ }
+ }
+
+ bool ellipsis = false;
+
+ var i = 1;
+ weak List<weak FormalParameter> params_it = params;
+ foreach (Expression arg in expr.get_argument_list ()) {
+ /* explicitly use strong reference as ccall gets
+ * unrefed at end of inner block
+ */
+ ref CCodeExpression cexpr = (CCodeExpression) arg.ccodenode;
+ if (params_it != null) {
+ var param = (FormalParameter) params_it.data;
+ ellipsis = param.ellipsis;
+ if (!ellipsis) {
+ if (param.type_reference.data_type != null
+ && param.type_reference.data_type.is_reference_type ()
+ && arg.static_type.data_type != null) {
+ if (!param.no_array_length && param.type_reference.data_type is Array) {
+ var arr = (Array) param.type_reference.data_type;
+ for (int dim = 1; dim <= arr.rank; dim++) {
+ ccall.add_argument (get_array_length_cexpression (arg, dim));
+ }
+ }
+ if (param.type_reference.data_type != arg.static_type.data_type) {
+ // FIXME: use C cast if debugging disabled
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (param.type_reference.data_type.get_upper_case_cname (null)));
+ ccall.add_argument (cexpr);
+ cexpr = ccall;
+ }
+ } else if (param.type_reference.data_type is Callback) {
+ cexpr = new CCodeCastExpression (cexpr, param.type_reference.data_type.get_cname ());
+ } else if (param.type_reference.data_type == null
+ && arg.static_type.data_type is Struct) {
+ /* convert integer to pointer if this is a generic method parameter */
+ var st = (Struct) arg.static_type.data_type;
+ if (st == bool_type.data_type || st.is_integer_type ()) {
+ var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GINT_TO_POINTER"));
+ cconv.add_argument (cexpr);
+ cexpr = cconv;
+ }
+ }
+ }
+ }
+
+ ccall.add_argument (cexpr);
+ i++;
+
+ if (params_it != null) {
+ params_it = params_it.next;
+ }
+ }
+ while (params_it != null) {
+ var param = (FormalParameter) params_it.data;
+
+ if (param.ellipsis) {
+ ellipsis = true;
+ break;
+ }
+
+ if (param.default_expression == null) {
+ Report.error (expr.source_reference, "no default expression for argument %d".printf (i));
+ return;
+ }
+
+ /* evaluate default expression here as the code
+ * generator might not have visited the formal
+ * parameter yet */
+ param.default_expression.accept (this);
+
+ if (!param.no_array_length && param.type_reference != null &&
+ param.type_reference.data_type is Array) {
+ var arr = (Array) param.type_reference.data_type;
+ for (int dim = 1; dim <= arr.rank; dim++) {
+ ccall.add_argument (get_array_length_cexpression (param.default_expression, dim));
+ }
+ }
+
+ ccall.add_argument ((CCodeExpression) param.default_expression.ccodenode);
+ i++;
+
+ params_it = params_it.next;
+ }
+
+ if (m != null && m.instance && m.instance_last) {
+ ccall.add_argument (instance);
+ } else if (ellipsis) {
+ /* ensure variable argument list ends with NULL
+ * except when using printf-style arguments */
+ if (m == null || !m.printf_format) {
+ ccall.add_argument (new CCodeConstant ("NULL"));
+ }
+ }
+
+ if (m != null && m.instance && m.returns_modified_pointer) {
+ expr.ccodenode = new CCodeAssignment (instance, ccall);
+ } else {
+ /* cast pointer to actual type if this is a generic method return value */
+ if (m != null && m.return_type.type_parameter != null && expr.static_type.data_type != null) {
+ if (expr.static_type.data_type is Struct) {
+ var st = (Struct) expr.static_type.data_type;
+ if (st == uint_type.data_type) {
+ var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_UINT"));
+ cconv.add_argument (ccall);
+ ccall = cconv;
+ } else if (st == bool_type.data_type || st.is_integer_type ()) {
+ var cconv = new CCodeFunctionCall (new CCodeIdentifier ("GPOINTER_TO_INT"));
+ cconv.add_argument (ccall);
+ ccall = cconv;
+ }
+ }
+ }
+
+ expr.ccodenode = ccall;
+
+ visit_expression (expr);
+ }
+
+ if (m is ArrayResizeMethod) {
+ // FIXME: size expression must not be evaluated twice at runtime (potential side effects)
+ var new_size = (CCodeExpression) ((CodeNode) expr.get_argument_list ().data).ccodenode;
+
+ var temp_decl = get_temp_variable_declarator (int_type);
+ var temp_ref = new CCodeIdentifier (temp_decl.name);
+
+ temp_vars.prepend (temp_decl);
+
+ /* memset needs string.h */
+ string_h_needed = true;
+
+ var clen = get_array_length_cexpression (ma.inner, 1);
+ var celems = (CCodeExpression)ma.inner.ccodenode;
+ var csizeof = new CCodeIdentifier ("sizeof (%s)".printf (ma.inner.static_type.data_type.get_cname ()));
+ var cdelta = new CCodeParenthesizedExpression (new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, temp_ref, clen));
+ var ccheck = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, temp_ref, clen);
+
+ var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
+ czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, celems, clen));
+ czero.add_argument (new CCodeConstant ("0"));
+ czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeof, cdelta));
+
+ var ccomma = new CCodeCommaExpression ();
+ ccomma.append_expression (new CCodeAssignment (temp_ref, new_size));
+ ccomma.append_expression ((CCodeExpression) expr.ccodenode);
+ ccomma.append_expression (new CCodeConditionalExpression (ccheck, czero, new CCodeConstant ("NULL")));
+ ccomma.append_expression (new CCodeAssignment (get_array_length_cexpression (ma.inner, 1), temp_ref));
+
+ expr.ccodenode = ccomma;
+ }
+ }
+
+ public override void visit_element_access (ElementAccess! expr)
+ {
+ List<weak Expression> indices = expr.get_indices ();
+ int rank = indices.length ();
+
+ if (rank == 1) {
+ /* FIXME: had to add Expression cast due to possible compiler bug */
+ expr.ccodenode = new CCodeElementAccess ((CCodeExpression)expr.container.ccodenode, (CCodeExpression)((Expression)indices.first ().data).ccodenode);
+ } else {
+ expr.error = true;
+ Report.error (expr.source_reference, "Arrays with more then one dimension are not supported yet");
+ return;
+ }
+
+ visit_expression (expr);
+ }
+
+ public override void visit_base_access (BaseAccess! expr) {
+ expr.ccodenode = new InstanceCast (new CCodeIdentifier ("self"), expr.static_type.data_type);
+ }
+
+ public override void visit_postfix_expression (PostfixExpression! expr) {
+ MemberAccess ma = find_property_access (expr.inner);
+ if (ma != null) {
+ // property postfix expression
+ var prop = (Property) ma.symbol_reference.node;
+
+ var ccomma = new CCodeCommaExpression ();
+
+ // assign current value to temp variable
+ var temp_decl = get_temp_variable_declarator (prop.type_reference);
+ temp_vars.prepend (temp_decl);
+ ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_decl.name), (CCodeExpression) expr.inner.ccodenode));
+
+ // increment/decrement property
+ var op = expr.increment ? CCodeBinaryOperator.PLUS : CCodeBinaryOperator.MINUS;
+ var cexpr = new CCodeBinaryExpression (op, new CCodeIdentifier (temp_decl.name), new CCodeConstant ("1"));
+ var ccall = get_property_set_call (prop, ma, cexpr);
+ ccomma.append_expression (ccall);
+
+ // return previous value
+ ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
+
+ expr.ccodenode = ccomma;
+ return;
+ }
+
+ var op = expr.increment ? CCodeUnaryOperator.POSTFIX_INCREMENT : CCodeUnaryOperator.POSTFIX_DECREMENT;
+
+ expr.ccodenode = new CCodeUnaryExpression (op, (CCodeExpression) expr.inner.ccodenode);
+
+ visit_expression (expr);
+ }
+
+ private MemberAccess find_property_access (Expression! expr) {
+ if (expr is ParenthesizedExpression) {
+ var pe = (ParenthesizedExpression) expr;
+ return find_property_access (pe.inner);
+ }
+
+ if (!(expr is MemberAccess)) {
+ return null;
+ }
+
+ var ma = (MemberAccess) expr;
+ if (ma.symbol_reference.node is Property) {
+ return ma;
+ }
+
+ return null;
+ }
+
+ private ref CCodeExpression get_ref_expression (Expression! expr) {
+ /* (temp = expr, temp == NULL ? NULL : ref (temp))
+ *
+ * can be simplified to
+ * ref (expr)
+ * if static type of expr is non-null
+ */
+
+ if (expr.static_type.data_type == null &&
+ expr.static_type.type_parameter != null) {
+ Report.warning (expr.source_reference, "Missing generics support for memory management");
+ return (CCodeExpression) expr.ccodenode;
+ }
+
+ string ref_function;
+ if (expr.static_type.data_type.is_reference_counting ()) {
+ ref_function = expr.static_type.data_type.get_ref_function ();
+ } else {
+ if (expr.static_type.data_type != string_type.data_type) {
+ // duplicating non-reference counted structs may cause side-effects (and performance issues)
+ Report.warning (expr.source_reference, "duplicating %s instance, use weak variable or explicitly invoke copy method".printf (expr.static_type.data_type.name));
+ }
+ ref_function = expr.static_type.data_type.get_dup_function ();
+ }
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (ref_function));
+
+ if (expr.static_type.non_null) {
+ ccall.add_argument ((CCodeExpression) expr.ccodenode);
+
+ return ccall;
+ } else {
+ var decl = get_temp_variable_declarator (expr.static_type, false);
+ temp_vars.prepend (decl);
+
+ var ctemp = new CCodeIdentifier (decl.name);
+
+ var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, new CCodeConstant ("NULL"));
+
+ ccall.add_argument (ctemp);
+
+ var ccomma = new CCodeCommaExpression ();
+ ccomma.append_expression (new CCodeAssignment (ctemp, (CCodeExpression) expr.ccodenode));
+
+ if (ref_function == "g_list_copy") {
+ bool is_ref = false;
+ bool is_class = false;
+ bool is_interface = false;
+
+ foreach (TypeReference type_arg in expr.static_type.get_type_arguments ()) {
+ is_ref |= type_arg.takes_ownership;
+ is_class |= type_arg.data_type is Class;
+ is_interface |= type_arg.data_type is Interface;
+ }
+
+ if (is_ref && (is_class || is_interface)) {
+ var crefcall = new CCodeFunctionCall (new CCodeIdentifier ("g_list_foreach"));
+
+ crefcall.add_argument (ctemp);
+ crefcall.add_argument (new CCodeIdentifier ("(GFunc) g_object_ref"));
+ crefcall.add_argument (new CCodeConstant ("NULL"));
+
+ ccomma.append_expression (crefcall);
+ }
+ }
+
+ ccomma.append_expression (new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), ccall));
+
+ return ccomma;
+ }
+ }
+
+ private void visit_expression (Expression! expr) {
+ if (expr.static_type != null &&
+ expr.static_type.transfers_ownership &&
+ expr.static_type.floating_reference) {
+ /* constructor of GInitiallyUnowned subtype
+ * returns floating reference, sink it
+ */
+ var csink = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref_sink"));
+ csink.add_argument ((CCodeExpression) expr.ccodenode);
+
+ expr.ccodenode = csink;
+ }
+
+ if (expr.ref_leaked) {
+ var decl = get_temp_variable_declarator (expr.static_type);
+ temp_vars.prepend (decl);
+ temp_ref_vars.prepend (decl);
+ expr.ccodenode = new CCodeParenthesizedExpression (new CCodeAssignment (new CCodeIdentifier (decl.name), (CCodeExpression) expr.ccodenode));
+ } else if (expr.ref_missing) {
+ expr.ccodenode = get_ref_expression (expr);
+ }
+ }
+
+ public override void visit_end_object_creation_expression (ObjectCreationExpression! expr) {
+ if (expr.symbol_reference == null) {
+ // no creation method
+ if (expr.type_reference.data_type is Class) {
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_new"));
+
+ ccall.add_argument (new CCodeConstant (expr.type_reference.data_type.get_type_id ()));
+
+ ccall.add_argument (new CCodeConstant ("NULL"));
+
+ expr.ccodenode = ccall;
+ } else if (expr.type_reference.data_type == list_type ||
+ expr.type_reference.data_type == slist_type) {
+ // NULL is an empty list
+ expr.ccodenode = new CCodeConstant ("NULL");
+ } else {
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
+
+ ccall.add_argument (new CCodeConstant (expr.type_reference.data_type.get_cname ()));
+
+ ccall.add_argument (new CCodeConstant ("1"));
+
+ expr.ccodenode = ccall;
+ }
+ } else {
+ // use creation method
+ var m = (Method) expr.symbol_reference.node;
+ var params = m.get_parameters ();
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
+
+ if (expr.type_reference.data_type is Class) {
+ foreach (TypeReference type_arg in expr.type_reference.get_type_arguments ()) {
+ if (type_arg.takes_ownership) {
+ ccall.add_argument (get_destroy_func_expression (type_arg));
+ } else {
+ ccall.add_argument (new CCodeConstant ("NULL"));
+ }
+ }
+ }
+
+ bool ellipsis = false;
+
+ int i = 1;
+ weak List<weak FormalParameter> params_it = params;
+ foreach (Expression arg in expr.get_argument_list ()) {
+ /* explicitly use strong reference as ccall gets
+ * unrefed at end of inner block
+ */
+ ref CCodeExpression cexpr = (CCodeExpression) arg.ccodenode;
+ if (params_it != null) {
+ var param = (FormalParameter) params_it.data;
+ ellipsis = param.ellipsis;
+ if (!param.ellipsis
+ && param.type_reference.data_type != null
+ && param.type_reference.data_type.is_reference_type ()
+ && arg.static_type.data_type != null
+ && param.type_reference.data_type != arg.static_type.data_type) {
+ // FIXME: use C cast if debugging disabled
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (param.type_reference.data_type.get_upper_case_cname (null)));
+ ccall.add_argument (cexpr);
+ cexpr = ccall;
+ }
+ }
+
+ ccall.add_argument (cexpr);
+ i++;
+
+ if (params_it != null) {
+ params_it = params_it.next;
+ }
+ }
+ while (params_it != null) {
+ var param = (FormalParameter) params_it.data;
+
+ if (param.ellipsis) {
+ ellipsis = true;
+ break;
+ }
+
+ if (param.default_expression == null) {
+ Report.error (expr.source_reference, "no default expression for argument %d".printf (i));
+ return;
+ }
+
+ /* evaluate default expression here as the code
+ * generator might not have visited the formal
+ * parameter yet */
+ param.default_expression.accept (this);
+
+ ccall.add_argument ((CCodeExpression) param.default_expression.ccodenode);
+ i++;
+
+ params_it = params_it.next;
+ }
+
+ if (ellipsis) {
+ // ensure variable argument list ends with NULL
+ ccall.add_argument (new CCodeConstant ("NULL"));
+ }
+
+ expr.ccodenode = ccall;
+ }
+
+ visit_expression (expr);
+ }
+
+ public override void visit_typeof_expression (TypeofExpression! expr) {
+ expr.ccodenode = new CCodeIdentifier (expr.type_reference.data_type.get_type_id ());
+ }
+
+ public override void visit_unary_expression (UnaryExpression! expr) {
+ CCodeUnaryOperator op;
+ if (expr.operator == UnaryOperator.PLUS) {
+ op = CCodeUnaryOperator.PLUS;
+ } else if (expr.operator == UnaryOperator.MINUS) {
+ op = CCodeUnaryOperator.MINUS;
+ } else if (expr.operator == UnaryOperator.LOGICAL_NEGATION) {
+ op = CCodeUnaryOperator.LOGICAL_NEGATION;
+ } else if (expr.operator == UnaryOperator.BITWISE_COMPLEMENT) {
+ op = CCodeUnaryOperator.BITWISE_COMPLEMENT;
+ } else if (expr.operator == UnaryOperator.INCREMENT) {
+ op = CCodeUnaryOperator.PREFIX_INCREMENT;
+ } else if (expr.operator == UnaryOperator.DECREMENT) {
+ op = CCodeUnaryOperator.PREFIX_DECREMENT;
+ } else if (expr.operator == UnaryOperator.REF) {
+ op = CCodeUnaryOperator.ADDRESS_OF;
+ } else if (expr.operator == UnaryOperator.OUT) {
+ op = CCodeUnaryOperator.ADDRESS_OF;
+ }
+ expr.ccodenode = new CCodeUnaryExpression (op, (CCodeExpression) expr.inner.ccodenode);
+
+ visit_expression (expr);
+ }
+
+ public override void visit_cast_expression (CastExpression! expr) {
+ if (expr.type_reference.data_type is Class || expr.type_reference.data_type is Interface) {
+ // GObject cast
+ expr.ccodenode = new InstanceCast ((CCodeExpression) expr.inner.ccodenode, expr.type_reference.data_type);
+ } else {
+ expr.ccodenode = new CCodeCastExpression ((CCodeExpression) expr.inner.ccodenode, expr.type_reference.get_cname ());
+ }
+
+ visit_expression (expr);
+ }
+
+ public override void visit_pointer_indirection (PointerIndirection! expr) {
+ expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, (CCodeExpression) expr.inner.ccodenode);
+ }
+
+ public override void visit_addressof_expression (AddressofExpression! expr) {
+ expr.ccodenode = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, (CCodeExpression) expr.inner.ccodenode);
+ }
+
+ public override void visit_reference_transfer_expression (ReferenceTransferExpression! expr) {
+ /* (tmp = var, var = null, tmp) */
+ var ccomma = new CCodeCommaExpression ();
+ var temp_decl = get_temp_variable_declarator (expr.static_type);
+ temp_vars.prepend (temp_decl);
+ var cvar = new CCodeIdentifier (temp_decl.name);
+
+ ccomma.append_expression (new CCodeAssignment (cvar, (CCodeExpression) expr.inner.ccodenode));
+ ccomma.append_expression (new CCodeAssignment ((CCodeExpression) expr.inner.ccodenode, new CCodeConstant ("NULL")));
+ ccomma.append_expression (cvar);
+ expr.ccodenode = ccomma;
+
+ visit_expression (expr);
+ }
+
+ public override void visit_binary_expression (BinaryExpression! expr) {
+ CCodeBinaryOperator op;
+ if (expr.operator == BinaryOperator.PLUS) {
+ op = CCodeBinaryOperator.PLUS;
+ } else if (expr.operator == BinaryOperator.MINUS) {
+ op = CCodeBinaryOperator.MINUS;
+ } else if (expr.operator == BinaryOperator.MUL) {
+ op = CCodeBinaryOperator.MUL;
+ } else if (expr.operator == BinaryOperator.DIV) {
+ op = CCodeBinaryOperator.DIV;
+ } else if (expr.operator == BinaryOperator.MOD) {
+ op = CCodeBinaryOperator.MOD;
+ } else if (expr.operator == BinaryOperator.SHIFT_LEFT) {
+ op = CCodeBinaryOperator.SHIFT_LEFT;
+ } else if (expr.operator == BinaryOperator.SHIFT_RIGHT) {
+ op = CCodeBinaryOperator.SHIFT_RIGHT;
+ } else if (expr.operator == BinaryOperator.LESS_THAN) {
+ op = CCodeBinaryOperator.LESS_THAN;
+ } else if (expr.operator == BinaryOperator.GREATER_THAN) {
+ op = CCodeBinaryOperator.GREATER_THAN;
+ } else if (expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL) {
+ op = CCodeBinaryOperator.LESS_THAN_OR_EQUAL;
+ } else if (expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
+ op = CCodeBinaryOperator.GREATER_THAN_OR_EQUAL;
+ } else if (expr.operator == BinaryOperator.EQUALITY) {
+ op = CCodeBinaryOperator.EQUALITY;
+ } else if (expr.operator == BinaryOperator.INEQUALITY) {
+ op = CCodeBinaryOperator.INEQUALITY;
+ } else if (expr.operator == BinaryOperator.BITWISE_AND) {
+ op = CCodeBinaryOperator.BITWISE_AND;
+ } else if (expr.operator == BinaryOperator.BITWISE_OR) {
+ op = CCodeBinaryOperator.BITWISE_OR;
+ } else if (expr.operator == BinaryOperator.BITWISE_XOR) {
+ op = CCodeBinaryOperator.BITWISE_XOR;
+ } else if (expr.operator == BinaryOperator.AND) {
+ op = CCodeBinaryOperator.AND;
+ } else if (expr.operator == BinaryOperator.OR) {
+ op = CCodeBinaryOperator.OR;
+ }
+
+ var cleft = (CCodeExpression) expr.left.ccodenode;
+ var cright = (CCodeExpression) expr.right.ccodenode;
+
+ if (expr.operator == BinaryOperator.EQUALITY ||
+ expr.operator == BinaryOperator.INEQUALITY) {
+ if (expr.left.static_type != null && expr.right.static_type != null &&
+ expr.left.static_type.data_type is Class && expr.right.static_type.data_type is Class) {
+ var left_cl = (Class) expr.left.static_type.data_type;
+ var right_cl = (Class) expr.right.static_type.data_type;
+
+ if (left_cl != right_cl) {
+ if (left_cl.is_subtype_of (right_cl)) {
+ cleft = new InstanceCast (cleft, right_cl);
+ } else if (right_cl.is_subtype_of (left_cl)) {
+ cright = new InstanceCast (cright, left_cl);
+ }
+ }
+ }
+ }
+
+ expr.ccodenode = new CCodeBinaryExpression (op, cleft, cright);
+
+ visit_expression (expr);
+ }
+
+ public override void visit_type_check (TypeCheck! expr) {
+ var ccheck = new CCodeFunctionCall (new CCodeIdentifier (expr.type_reference.data_type.get_upper_case_cname ("IS_")));
+ ccheck.add_argument ((CCodeExpression) expr.expression.ccodenode);
+ expr.ccodenode = ccheck;
+ }
+
+ public override void visit_conditional_expression (ConditionalExpression! expr) {
+ expr.ccodenode = new CCodeConditionalExpression ((CCodeExpression) expr.condition.ccodenode, (CCodeExpression) expr.true_expression.ccodenode, (CCodeExpression) expr.false_expression.ccodenode);
+ }
+
+ public override void visit_end_lambda_expression (LambdaExpression! l) {
+ l.ccodenode = new CCodeIdentifier (l.method.get_cname ());
+ }
+
+ public override void visit_end_assignment (Assignment! a) {
+ MemberAccess ma = null;
+
+ if (a.left is MemberAccess) {
+ ma = (MemberAccess)a.left;
+ }
+
+ if (a.left.symbol_reference != null && a.left.symbol_reference.node is Property) {
+ var prop = (Property) a.left.symbol_reference.node;
+
+ if (current_class != null && ma.inner == null && in_creation_method) {
+ // this property is used as a construction parameter
+ var cpointer = new CCodeIdentifier ("__params_it");
+
+ var ccomma = new CCodeCommaExpression ();
+ // set name in array for current parameter
+ var cnamemember = new CCodeMemberAccess.pointer (cpointer, "name");
+ var cnameassign = new CCodeAssignment (cnamemember, prop.get_canonical_cconstant ());
+ ccomma.append_expression (cnameassign);
+
+ var gvaluearg = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (cpointer, "value"));
+
+ // initialize GValue in array for current parameter
+ var cvalueinit = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
+ cvalueinit.add_argument (gvaluearg);
+ cvalueinit.add_argument (new CCodeIdentifier (prop.type_reference.data_type.get_type_id ()));
+ ccomma.append_expression (cvalueinit);
+
+ // set GValue for current parameter
+ var cvalueset = new CCodeFunctionCall (get_value_setter_function (prop.type_reference));
+ cvalueset.add_argument (gvaluearg);
+ cvalueset.add_argument ((CCodeExpression) a.right.ccodenode);
+ ccomma.append_expression (cvalueset);
+
+ // move pointer to next parameter in array
+ ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, cpointer));
+
+ a.ccodenode = ccomma;
+ } else {
+ ref CCodeExpression cexpr = (CCodeExpression) a.right.ccodenode;
+
+ if (!prop.no_accessor_method
+ && prop.type_reference.data_type != null
+ && prop.type_reference.data_type.is_reference_type ()
+ && a.right.static_type.data_type != null
+ && prop.type_reference.data_type != a.right.static_type.data_type) {
+ /* cast is necessary */
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier (prop.type_reference.data_type.get_upper_case_cname (null)));
+ ccast.add_argument (cexpr);
+ cexpr = ccast;
+ }
+
+ if (a.operator != AssignmentOperator.SIMPLE) {
+ CCodeBinaryOperator cop;
+ if (a.operator == AssignmentOperator.BITWISE_OR) {
+ cop = CCodeBinaryOperator.BITWISE_OR;
+ } else if (a.operator == AssignmentOperator.BITWISE_AND) {
+ cop = CCodeBinaryOperator.BITWISE_AND;
+ } else if (a.operator == AssignmentOperator.BITWISE_XOR) {
+ cop = CCodeBinaryOperator.BITWISE_XOR;
+ } else if (a.operator == AssignmentOperator.ADD) {
+ cop = CCodeBinaryOperator.PLUS;
+ } else if (a.operator == AssignmentOperator.SUB) {
+ cop = CCodeBinaryOperator.MINUS;
+ } else if (a.operator == AssignmentOperator.MUL) {
+ cop = CCodeBinaryOperator.MUL;
+ } else if (a.operator == AssignmentOperator.DIV) {
+ cop = CCodeBinaryOperator.DIV;
+ } else if (a.operator == AssignmentOperator.PERCENT) {
+ cop = CCodeBinaryOperator.MOD;
+ } else if (a.operator == AssignmentOperator.SHIFT_LEFT) {
+ cop = CCodeBinaryOperator.SHIFT_LEFT;
+ } else if (a.operator == AssignmentOperator.SHIFT_RIGHT) {
+ cop = CCodeBinaryOperator.SHIFT_RIGHT;
+ }
+ cexpr = new CCodeBinaryExpression (cop, (CCodeExpression) a.left.ccodenode, new CCodeParenthesizedExpression (cexpr));
+ }
+
+ var ccall = get_property_set_call (prop, ma, cexpr);
+
+ // assignments are expressions, so return the current property value
+ var ccomma = new CCodeCommaExpression ();
+ ccomma.append_expression (ccall); // update property
+ ccomma.append_expression ((CCodeExpression) ma.ccodenode); // current property value
+
+ a.ccodenode = ccomma;
+ }
+ } else if (a.left.symbol_reference != null && a.left.symbol_reference.node is Signal) {
+ var sig = (Signal) a.left.symbol_reference.node;
+
+ var m = (Method) a.right.symbol_reference.node;
+
+ string connect_func;
+ bool disconnect = false;
+
+ if (a.operator == AssignmentOperator.ADD) {
+ connect_func = "g_signal_connect_object";
+ if (!m.instance) {
+ connect_func = "g_signal_connect";
+ }
+ } else if (a.operator == AssignmentOperator.SUB) {
+ connect_func = "g_signal_handlers_disconnect_matched";
+ disconnect = true;
+ } else {
+ a.error = true;
+ Report.error (a.source_reference, "Specified compound assignment type for signals not supported.");
+ return;
+ }
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (connect_func));
+
+ if (ma.inner != null) {
+ ccall.add_argument ((CCodeExpression) ma.inner.ccodenode);
+ } else {
+ ccall.add_argument (new CCodeIdentifier ("self"));
+ }
+
+ if (!disconnect) {
+ ccall.add_argument (sig.get_canonical_cconstant ());
+ } else {
+ ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
+
+ // get signal id
+ var ccomma = new CCodeCommaExpression ();
+ var temp_decl = get_temp_variable_declarator (uint_type);
+ temp_vars.prepend (temp_decl);
+ var parse_call = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_parse_name"));
+ parse_call.add_argument (sig.get_canonical_cconstant ());
+ var decl_type = (DataType) sig.symbol.parent_symbol.node;
+ parse_call.add_argument (new CCodeIdentifier (decl_type.get_type_id ()));
+ parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_decl.name)));
+ parse_call.add_argument (new CCodeConstant ("NULL"));
+ parse_call.add_argument (new CCodeConstant ("FALSE"));
+ ccomma.append_expression (parse_call);
+ ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
+
+ ccall.add_argument (ccomma);
+
+ ccall.add_argument (new CCodeConstant ("0"));
+ ccall.add_argument (new CCodeConstant ("NULL"));
+ }
+
+ ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier (m.get_cname ()), "GCallback"));
+
+ if (m.instance) {
+ if (a.right is MemberAccess) {
+ var right_ma = (MemberAccess) a.right;
+ if (right_ma.inner != null) {
+ ccall.add_argument ((CCodeExpression) right_ma.inner.ccodenode);
+ } else {
+ ccall.add_argument (new CCodeIdentifier ("self"));
+ }
+ } else if (a.right is LambdaExpression) {
+ ccall.add_argument (new CCodeIdentifier ("self"));
+ }
+ if (!disconnect) {
+ ccall.add_argument (new CCodeConstant ("0"));
+ }
+ } else {
+ ccall.add_argument (new CCodeConstant ("NULL"));
+ }
+
+ a.ccodenode = ccall;
+ } else {
+ /* explicitly use strong reference as ccast gets
+ * unrefed at end of inner block
+ */
+ ref CCodeExpression rhs = (CCodeExpression) a.right.ccodenode;
+
+ if (a.left.static_type.data_type != null
+ && a.right.static_type.data_type != null
+ && a.left.static_type.data_type.is_reference_type ()
+ && a.right.static_type.data_type != a.left.static_type.data_type) {
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier (a.left.static_type.data_type.get_upper_case_cname (null)));
+ ccast.add_argument (rhs);
+ rhs = ccast;
+ }
+
+ bool unref_old = (memory_management && a.left.static_type.takes_ownership);
+ bool array = false;
+ if (a.left.static_type.data_type is Array) {
+ array = !(get_array_length_cexpression (a.left, 1) is CCodeConstant);
+ }
+
+ if (unref_old || array) {
+ var ccomma = new CCodeCommaExpression ();
+
+ var temp_decl = get_temp_variable_declarator (a.left.static_type);
+ temp_vars.prepend (temp_decl);
+ ccomma.append_expression (new CCodeAssignment (new CCodeIdentifier (temp_decl.name), rhs));
+ if (unref_old) {
+ /* unref old value */
+ ccomma.append_expression (get_unref_expression ((CCodeExpression) a.left.ccodenode, a.left.static_type));
+ }
+
+ if (array) {
+ var lhs_array_len = get_array_length_cexpression (a.left, 1);
+ var rhs_array_len = get_array_length_cexpression (a.right, 1);
+ ccomma.append_expression (new CCodeAssignment (lhs_array_len, rhs_array_len));
+ }
+
+ ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
+
+ rhs = ccomma;
+ }
+
+ var cop = CCodeAssignmentOperator.SIMPLE;
+ if (a.operator == AssignmentOperator.BITWISE_OR) {
+ cop = CCodeAssignmentOperator.BITWISE_OR;
+ } else if (a.operator == AssignmentOperator.BITWISE_AND) {
+ cop = CCodeAssignmentOperator.BITWISE_AND;
+ } else if (a.operator == AssignmentOperator.BITWISE_XOR) {
+ cop = CCodeAssignmentOperator.BITWISE_XOR;
+ } else if (a.operator == AssignmentOperator.ADD) {
+ cop = CCodeAssignmentOperator.ADD;
+ } else if (a.operator == AssignmentOperator.SUB) {
+ cop = CCodeAssignmentOperator.SUB;
+ } else if (a.operator == AssignmentOperator.MUL) {
+ cop = CCodeAssignmentOperator.MUL;
+ } else if (a.operator == AssignmentOperator.DIV) {
+ cop = CCodeAssignmentOperator.DIV;
+ } else if (a.operator == AssignmentOperator.PERCENT) {
+ cop = CCodeAssignmentOperator.PERCENT;
+ } else if (a.operator == AssignmentOperator.SHIFT_LEFT) {
+ cop = CCodeAssignmentOperator.SHIFT_LEFT;
+ } else if (a.operator == AssignmentOperator.SHIFT_RIGHT) {
+ cop = CCodeAssignmentOperator.SHIFT_RIGHT;
+ }
+
+ a.ccodenode = new CCodeAssignment ((CCodeExpression) a.left.ccodenode, rhs, cop);
+ }
+ }
+
+ private ref CCodeFunctionCall get_property_set_call (Property! prop, MemberAccess! ma, CCodeExpression! cexpr) {
+ var cl = (Class) prop.symbol.parent_symbol.node;
+ var set_func = "g_object_set";
+
+ if (!prop.no_accessor_method) {
+ set_func = "%s_set_%s".printf (cl.get_lower_case_cname (null), prop.name);
+ }
+
+ var ccall = new CCodeFunctionCall (new CCodeIdentifier (set_func));
+
+ /* target instance is first argument */
+ ref CCodeExpression instance;
+ var req_cast = false;
+
+ if (ma.inner == null) {
+ instance = new CCodeIdentifier ("self");
+ /* require casts for inherited properties */
+ req_cast = (prop.symbol.parent_symbol != current_type_symbol);
+ } else {
+ instance = (CCodeExpression) ma.inner.ccodenode;
+ /* require casts if the type of the used instance is
+ * different than the type which declared the property */
+ req_cast = prop.symbol.parent_symbol.node != ma.inner.static_type.data_type;
+ }
+
+ if (req_cast && ((DataType) prop.symbol.parent_symbol.node).is_reference_type ()) {
+ var ccast = new CCodeFunctionCall (new CCodeIdentifier (((DataType) prop.symbol.parent_symbol.node).get_upper_case_cname (null)));
+ ccast.add_argument (instance);
+ instance = ccast;
+ }
+
+ ccall.add_argument (instance);
+
+ if (prop.no_accessor_method) {
+ /* property name is second argument of g_object_set */
+ ccall.add_argument (prop.get_canonical_cconstant ());
+ }
+
+ ccall.add_argument (cexpr);
+
+ if (prop.no_accessor_method) {
+ ccall.add_argument (new CCodeConstant ("NULL"));
+ }
+
+ return ccall;
+ }
+}
diff --git a/vala/valacodenode.vala b/vala/valacodenode.vala
new file mode 100644
index 000000000..92df6fcb1
--- /dev/null
+++ b/vala/valacodenode.vala
@@ -0,0 +1,118 @@
+/* valacodenode.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * Represents a part of the parsed source code.
+ *
+ * Code nodes get created by the parser and are used throughout the whole
+ * compilation process.
+ */
+public abstract class Vala.CodeNode {
+ /**
+ * Parent of this code node.
+ */
+ public CodeNode parent_node { get; set; }
+
+ /**
+ * Symbol that corresponds to this code node.
+ */
+ public Symbol symbol { get; set; }
+
+ /**
+ * References the location in the source file where this code node has
+ * been written.
+ */
+ public SourceReference source_reference { get; set construct; }
+
+ /**
+ * Contains all attributes that have been specified for this code node.
+ */
+ public List<Attribute> attributes;
+
+ /**
+ * Generated CCodeNode that corresponds to this code node.
+ */
+ public CCodeNode ccodenode {
+ get {
+ return _ccodenode;
+ }
+ set {
+ if (source_reference != null) {
+ value.line = new CCodeLineDirective (
+ source_reference.file.filename,
+ source_reference.first_line);
+ }
+
+ _ccodenode = value;
+ }
+ }
+
+ /**
+ * Specifies whether a fatal error has been detected in this code node.
+ */
+ public bool error { get; set; }
+
+ /**
+ * Visits this code node and all children with the specified
+ * CodeVisitor.
+ *
+ * @param visitor the visitor to be called while traversing
+ */
+ public virtual void accept (CodeVisitor! visitor) {
+ }
+
+ public virtual void replace (CodeNode! old_node, CodeNode! new_node) {
+ }
+
+ /**
+ * Returns the specified attribute.
+ *
+ * @param name attribute name
+ * @return attribute
+ */
+ public Attribute get_attribute (string! name) {
+ // FIXME: use hash table
+ foreach (Attribute a in attributes) {
+ if (a.name == name) {
+ return a;
+ }
+ }
+
+ return null;
+ }
+
+ private CCodeNode _ccodenode;
+
+ /**
+ * Returns a string that represents this code node.
+ *
+ * @return a string representation
+ */
+ public virtual ref string! to_string () {
+ if (source_reference != null) {
+ return source_reference.to_string ();
+ }
+ return "(unknown)";
+ }
+}
diff --git a/vala/valacodevisitor.vala b/vala/valacodevisitor.vala
new file mode 100644
index 000000000..e5624f5f9
--- /dev/null
+++ b/vala/valacodevisitor.vala
@@ -0,0 +1,838 @@
+/* valacodevisitor.vala
+ *
+ * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
+ *
+ * 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>
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+using GLib;
+
+/**
+ * Abstract code node visitor for traversing source code tree.
+ */
+public abstract class Vala.CodeVisitor {
+ /**
+ * Visit operation called at beginning of source files.
+ *
+ * @param source_file a source file
+ */
+ public virtual void visit_begin_source_file (SourceFile! source_file) {
+ }
+
+ /**
+ * Visit operation called at end of source files.
+ *
+ * @param source_file a source file
+ */
+ public virtual void visit_end_source_file (SourceFile! source_file) {
+ }
+
+ /**
+ * Visit operation called at beginning of namespaces.
+ *
+ * @param ns a namespace
+ */
+ public virtual void visit_begin_namespace (Namespace! ns) {
+ }
+
+ /**
+ * Visit operation called at end of namespaces.
+ *
+ * @param ns a namespace
+ */
+ public virtual void visit_end_namespace (Namespace! ns) {
+ }
+
+ /**
+ * Visit operation called at beginning of classes.
+ *
+ * @param cl a class
+ */
+ public virtual void visit_begin_class (Class! cl) {
+ }
+
+ /**
+ * Visit operation called at end of classes.
+ *
+ * @param cl a class
+ */
+ public virtual void visit_end_class (Class! cl) {
+ }
+
+ /**
+ * Visit operation called at beginning of structs.
+ *
+ * @param st a struct
+ */
+ public virtual void visit_begin_struct (Struct! st) {
+ }
+
+ /**
+ * Visit operation called at end of structs.
+ *
+ * @param st a struct
+ */
+ public virtual void visit_end_struct (Struct! st) {
+ }
+
+ /**
+ * Visit operation called at beginning of interfaces.
+ *
+ * @param iface an interface
+ */
+ public virtual void visit_begin_interface (Interface! iface) {
+ }
+
+ /**
+ * Visit operation called at end of interfaces.
+ *
+ * @param iface an interface
+ */
+ public virtual void visit_end_interface (Interface! iface) {
+ }
+
+ /**
+ * Visit operation called at beginning of enums.
+ *
+ * @param en an enum
+ */
+ public virtual void visit_begin_enum (Enum! en) {
+ }
+
+ /**
+ * Visit operation called at end of enums.
+ *
+ * @param en an enum
+ */
+ public virtual void visit_end_enum (Enum! en) {
+ }
+
+ /**
+ * Visit operation called for enum values.
+ *
+ * @param ev an enum value
+ */
+ public virtual void visit_enum_value (EnumValue! ev) {
+ }
+
+ /**
+ * Visit operation called at beginning of flags.
+ *
+ * @param fl a flags
+ */
+ public virtual void visit_begin_flags (Flags! fl) {
+ }
+
+ /**
+ * Visit operation called at end of flags.
+ *
+ * @param fl a flags
+ */
+ public virtual void visit_end_flags (Flags! fl) {
+ }
+
+ /**
+ * Visit operation called for flags values.
+ *
+ * @param fv an flags value
+ */
+ public virtual void visit_flags_value (FlagsValue! fv) {
+ }
+
+ /**
+ * Visit operation called at beginning of callbacks.
+ *
+ * @param cb a callback
+ */
+ public virtual void visit_begin_callback (Callback! cb) {
+ }
+
+ /**
+ * Visit operation called at end of callbacks.
+ *
+ * @param cb a callback
+ */
+ public virtual void visit_end_callback (Callback! cb) {
+ }
+
+ /**
+ * Visit operation called for Members.
+ *
+ * @param m a member
+ */
+ public virtual void visit_member (Member! m) {
+ }
+
+ /**
+ * Visit operation called for constants.
+ *
+ * @param c a constant
+ */
+ public virtual void visit_constant (Constant! c) {
+ }
+
+ /**
+ * Visit operation called for fields.
+ *
+ * @param f a field
+ */
+ public virtual void visit_field (Field! f) {
+ }
+
+ /**
+ * Visit operation called at beginning of methods.
+ *
+ * @param m a method
+ */
+ public virtual void visit_begin_method (Method! m) {
+ }
+
+ /**
+ * Visit operation called at end of methods.
+ *
+ * @param m a method
+ */
+ public virtual void visit_end_method (Method! m) {
+ }
+
+ /**
+ * Visit operation called at beginning of creation methods.
+ *
+ * @param m a method
+ */
+ public virtual void visit_begin_creation_method (CreationMethod! m) {
+ }
+
+ /**
+ * Visit operation called at end of creation methods.
+ *
+ * @param m a method
+ */
+ public virtual void visit_end_creation_method (CreationMethod! m) {
+ }
+
+ /**
+ * Visit operation called for formal parameters.
+ *
+ * @param p a formal parameter
+ */
+ public virtual void visit_formal_parameter (FormalParameter! p) {
+ }
+
+ /**
+ * Visit operation called at beginning of properties.
+ *
+ * @param prop a property
+ */
+ public virtual void visit_begin_property (Property! prop) {
+ }
+
+ /**
+ * Visit operation called at end of properties.
+ *
+ * @param prop a property
+ */
+ public virtual void visit_end_property (Property! prop) {
+ }
+
+ /**
+ * Visit operation called at beginning of property accessors.
+ *
+ * @param acc a property accessor
+ */
+ public virtual void visit_begin_property_accessor (PropertyAccessor! acc) {
+ }
+
+ /**
+ * Visit operation called at end of property accessors.
+ *
+ * @param acc a property accessor
+ */
+ public virtual void visit_end_property_accessor (PropertyAccessor! acc) {
+ }
+
+ /**
+ * Visit operation called at beginning of signals.
+ *
+ * @param sig a signal
+ */
+ public virtual void visit_begin_signal (Signal! sig) {
+ }
+
+ /**
+ * Visit operation called at end of signals.
+ *
+ * @param sig a signal
+ */
+ public virtual void visit_end_signal (Signal! sig) {
+ }
+
+ /**
+ * Visit operation called at beginning of constructors.
+ *
+ * @param c a constructor
+ */
+ public virtual void visit_begin_constructor (Constructor! c) {
+ }
+
+ /**
+ * Visit operation called at end of constructors.
+ *
+ * @param c a constructor
+ */
+ public virtual void visit_end_constructor (Constructor! c) {
+ }
+
+ /**
+ * Visit operation called at beginning of destructors.
+ *
+ * @param d a destructor
+ */
+ public virtual void visit_begin_destructor (Destructor! d) {
+ }
+
+ /**
+ * Visit operation called at end of destructors.
+ *
+ * @param d a destructor
+ */
+ public virtual void visit_end_destructor (Destructor! d) {
+ }
+
+ /**
+ * Visit operation called for named arguments.
+ *
+ * @param n a named argument
+ */
+ public virtual void visit_named_argument (NamedArgument! n) {
+ }
+
+ /**
+ * Visit operation called for type parameters.
+ *
+ * @param p a type parameter
+ */
+ public virtual void visit_type_parameter (TypeParameter! p) {
+ }
+
+ /**
+ * Visit operation called for namespace references.
+ *
+ * @param ns a namespace reference
+ */
+ public virtual void visit_namespace_reference (NamespaceReference! ns) {
+ }
+
+ /**
+ * Visit operation called for type references.
+ *
+ * @param type a type reference
+ */
+ public virtual void visit_type_reference (TypeReference! type) {
+ }
+
+ /**
+ * Visit operation called at beginning of blocks.
+ *
+ * @param b a block
+ */
+ public virtual void visit_begin_block (Block! b) {
+ }
+
+ /**
+ * Visit operation called at end of blocks.
+ *
+ * @param b a block
+ */
+ public virtual void visit_end_block (Block! b) {
+ }
+
+ /**
+ * Visit operation called for empty statements.
+ *
+ * @param stmt an empty statement
+ */
+ public virtual void visit_empty_statement (EmptyStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called for declaration statements.
+ *
+ * @param stmt a declaration statement
+ */
+ public virtual void visit_declaration_statement (DeclarationStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called for local variable declarations.
+ *
+ * @param decl a local variable declaration
+ */
+ public virtual void visit_local_variable_declaration (LocalVariableDeclaration! decl) {
+ }
+
+ /**
+ * Visit operation called for variable declarators.
+ *
+ * @param decl a variable declarator
+ */
+ public virtual void visit_variable_declarator (VariableDeclarator! decl) {
+ }
+
+ /**
+ * Visit operation called for initializer lists
+ *
+ * @param list an initializer list
+ */
+ public virtual void visit_begin_initializer_list (InitializerList! list) {
+ }
+
+ /**
+ * Visit operation called for initializer lists
+ *
+ * @param list an initializer list
+ */
+ public virtual void visit_end_initializer_list (InitializerList! list) {
+ }
+
+ /**
+ * Visit operation called for expression statements.
+ *
+ * @param stmt an expression statement
+ */
+ public virtual void visit_expression_statement (ExpressionStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called for if statements.
+ *
+ * @param stmt an if statement
+ */
+ public virtual void visit_if_statement (IfStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called for switch statements.
+ *
+ * @param stmt a switch statement
+ */
+ public virtual void visit_switch_statement (SwitchStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called for switch sections.
+ *
+ * @param section a switch section
+ */
+ public virtual void visit_switch_section (SwitchSection! section) {
+ }
+
+ /**
+ * Visit operation called for switch label.
+ *
+ * @param label a switch label
+ */
+ public virtual void visit_switch_label (SwitchLabel! label) {
+ }
+
+ /**
+ * Visit operation called for while statements.
+ *
+ * @param stmt an while statement
+ */
+ public virtual void visit_while_statement (WhileStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called for do statements.
+ *
+ * @param stmt a do statement
+ */
+ public virtual void visit_do_statement (DoStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called for for statements.
+ *
+ * @param stmt a for statement
+ */
+ public virtual void visit_for_statement (ForStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called at beginning of foreach statements.
+ *
+ * @param stmt a foreach statement
+ */
+ public virtual void visit_begin_foreach_statement (ForeachStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called at end of foreach statements.
+ *
+ * @param stmt a foreach statement
+ */
+ public virtual void visit_end_foreach_statement (ForeachStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called for break statements.
+ *
+ * @param stmt a break statement
+ */
+ public virtual void visit_break_statement (BreakStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called for continue statements.
+ *
+ * @param stmt a continue statement
+ */
+ public virtual void visit_continue_statement (ContinueStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called at beginning of return statements.
+ *
+ * @param stmt a return statement
+ */
+ public virtual void visit_begin_return_statement (ReturnStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called at end of return statements.
+ *
+ * @param stmt a return statement
+ */
+ public virtual void visit_end_return_statement (ReturnStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called at beginning of throw statements.
+ *
+ * @param stmt a throw statement
+ */
+ public virtual void visit_begin_throw_statement (ThrowStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called at end of throw statements.
+ *
+ * @param stmt a throw statement
+ */
+ public virtual void visit_end_throw_statement (ThrowStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called at beginning of try statements.
+ *
+ * @param stmt a try statement
+ */
+ public virtual void visit_begin_try_statement (TryStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called at end of try statements.
+ *
+ * @param stmt a try statement
+ */
+ public virtual void visit_end_try_statement (TryStatement! stmt) {
+ }
+
+ /**
+ * Visit operation called at beginning of catch clauses.
+ *
+ * @param clause a catch cluase
+ */
+ public virtual void visit_begin_catch_clause (CatchClause! clause) {
+ }
+
+ /**
+ * Visit operation called at end of catch clauses.
+ *
+ * @param clause a catch clause
+ */
+ public virtual void visit_end_catch_clause (CatchClause! clause) {
+ }
+
+ /**
+ * Visit operation called for lock statements before the body has been visited.
+ *
+ * @param stmt a lock statement
+ */
+ public virtual void visit_lock_statement (LockStatement! stmt) {
+ }
+
+ /**
+ * Visit operations called for array creation expresions.
+ *
+ * @param expr an array creation expression
+ */
+ public virtual void visit_begin_array_creation_expression (ArrayCreationExpression! expr) {
+ }
+
+ /**
+ * Visit operations called for array creation expresions.
+ *
+ * @param expr an array creation expression
+ */
+ public virtual void visit_end_array_creation_expression (ArrayCreationExpression! expr) {
+ }
+
+ /**
+ * Visit operation called for boolean literals.
+ *
+ * @param lit a boolean literal
+ */
+ public virtual void visit_boolean_literal (BooleanLiteral! lit) {
+ }
+
+ /**
+ * Visit operation called for character literals.
+ *
+ * @param lit a character literal
+ */
+ public virtual void visit_character_literal (CharacterLiteral! lit) {
+ }
+
+ /**
+ * Visit operation called for integer literals.
+ *
+ * @param lit an integer literal
+ */
+ public virtual void visit_integer_literal (IntegerLiteral! lit) {
+ }
+
+ /**
+ * Visit operation called for real literals.
+ *
+ * @param lit a real literal
+ */
+ public virtual void visit_real_literal (RealLiteral! lit) {
+ }
+
+ /**
+ * Visit operation called for string literals.
+ *
+ * @param lit a string literal
+ */
+ public virtual void visit_string_literal (StringLiteral! lit) {
+ }
+
+ /**
+ * Visit operation called for null literals.
+ *
+ * @param lit a null literal
+ */
+ public virtual void visit_null_literal (NullLiteral! lit) {
+ }
+
+ /**
+ * Visit operation called for literal expressions.
+ *
+ * @param expr a literal expression
+ */
+ public virtual void visit_literal_expression (LiteralExpression! expr) {
+ }
+
+ /**
+ * Visit operation called for parenthesized expressions.
+ *
+ * @param expr a parenthesized expression
+ */
+ public virtual void visit_parenthesized_expression (ParenthesizedExpression! expr) {
+ }
+
+ /**
+ * Visit operation called for member access expressions.
+ *
+ * @param expr a member access expression
+ */
+ public virtual void visit_member_access (MemberAccess! expr) {
+ }
+
+ /**
+ * Visit operation called at beginning of invocation expressions.
+ *
+ * @param expr an invocation expression
+ */
+ public virtual void visit_begin_invocation_expression (InvocationExpression! expr) {
+ }
+
+ /**
+ * Visit operation called at end of invocation expressions.
+ *
+ * @param expr an invocation expression
+ */
+ public virtual void visit_end_invocation_expression (InvocationExpression! expr) {
+ }
+
+ /**
+ * Visit operation called for element access expressions.
+ *
+ * @param expr an element access expression
+ */
+ public virtual void visit_element_access (ElementAccess! expr) {
+ }
+
+ /**
+ * Visit operation called for base access expressions.
+ *
+ * @param expr a base access expression
+ */
+ public virtual void visit_base_access (BaseAccess! expr) {
+ }
+
+ /**
+ * Visit operation called for postfix expressions.
+ *
+ * @param expr a postfix expression
+ */
+ public virtual void visit_postfix_expression (PostfixExpression! expr) {
+ }
+
+ /**
+ * Visit operation called at beginning of object creation
+ * expressions.
+ *
+ * @param expr an object creation expression
+ */
+ public virtual void visit_begin_object_creation_expression (ObjectCreationExpression! expr) {
+ }
+
+ /**
+ * Visit operation called at end of object creation expressions.
+ *
+ * @param expr an object creation expression
+ */
+ public virtual void visit_end_object_creation_expression (ObjectCreationExpression! expr) {
+ }
+
+ /**
+ * Visit operation called for typeof expressions.
+ *
+ * @param expr a typeof expression
+ */
+ public virtual void visit_typeof_expression (TypeofExpression! expr) {
+ }
+
+ /**
+ * Visit operation called for unary expressions.
+ *
+ * @param expr an unary expression
+ */
+ public virtual void visit_unary_expression (UnaryExpression! expr) {
+ }
+
+ /**
+ * Visit operation called for call expressions.
+ *
+ * @param expr a call expression
+ */
+ public virtual void visit_cast_expression (CastExpression! expr) {
+ }
+
+ /**
+ * Visit operation called for pointer indirections.
+ *
+ * @param expr a pointer indirection
+ */
+ public virtual void visit_pointer_indirection (PointerIndirection! expr) {
+ }
+
+ /**
+ * Visit operation called for address-of expressions.
+ *
+ * @param expr an address-of expression
+ */
+ public virtual void visit_addressof_expression (AddressofExpression! expr) {
+ }
+
+ /**
+ * Visit operation called for reference transfer expressions.
+ *
+ * @param expr a reference transfer expression
+ */
+ public virtual void visit_reference_transfer_expression (ReferenceTransferExpression! expr) {
+ }
+
+ /**
+ * Visit operation called for binary expressions.
+ *
+ * @param expr a binary expression
+ */
+ public virtual void visit_binary_expression (BinaryExpression! expr) {
+ }
+
+ /**
+ * Visit operation called for type checks.
+ *
+ * @param expr a type check expression
+ */
+ public virtual void visit_type_check (TypeCheck! expr) {
+ }
+
+ /**
+ * Visit operation called for conditional expressions.
+ *
+ * @param expr a conditional expression
+ */
+ public virtual void visit_conditional_expression (ConditionalExpression! expr) {
+ }
+
+ /**
+ * Visit operation called at beginning of lambda expressions.
+ *
+ * @param expr a lambda expression
+ */
+ public virtual void visit_begin_lambda_expression (LambdaExpression! expr) {
+ }
+
+ /**
+ * Visit operation called at end of lambda expressions.
+ *
+ * @param expr a lambda expression
+ */
+ public virtual void visit_end_lambda_expression (LambdaExpression! expr) {
+ }
+
+ /**
+ * Visit operation called at beginning of assignments.
+ *
+ * @param a an assignment
+ */
+ public virtual void visit_begin_assignment (Assignment! a) {
+ }
+
+ /**
+ * Visit operation called at end of assignments.
+ *
+ * @param a an assignment
+ */
+ public virtual void visit_end_assignment (Assignment! a) {
+ }
+
+ /**
+ * Visit operation called at end of full expressions.
+ *
+ * @param expr a full expression
+ */
+ public virtual void visit_end_full_expression (Expression! expr) {
+ }
+}
diff --git a/vala/valaconditionalexpression.vala b/vala/valaconditionalexpression.vala
new file mode 100644
index 000000000..92590dfcb
--- /dev/null
+++ b/vala/valaconditionalexpression.vala
@@ -0,0 +1,66 @@
+/* valaconditionalexpression.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;
+
+/**
+ * Represents a conditional expression in the source code.
+ */
+public class Vala.ConditionalExpression : Expression {
+ /**
+ * The condition.
+ */
+ public Expression! condition { get; set construct; }
+
+ /**
+ * The expression to be evaluated if the condition holds.
+ */
+ public Expression! true_expression { get; set construct; }
+
+ /**
+ * The expression to be evaluated if the condition doesn't hold.
+ */
+ public Expression! false_expression { get; set construct; }
+
+ /**
+ * Creates a new conditional expression.
+ *
+ * @param cond a condition
+ * @param true_expr expression to be evaluated if condition is true
+ * @param false_expr expression to be evaluated if condition is false
+ * @return newly created conditional expression
+ */
+ public ConditionalExpression (Expression! cond, Expression! true_expr, Expression! false_expr, SourceReference source) {
+ condition = cond;
+ true_expression = true_expr;
+ false_expression = false_expr;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ condition.accept (visitor);
+ true_expression.accept (visitor);
+ false_expression.accept (visitor);
+
+ visitor.visit_conditional_expression (this);
+ }
+}
diff --git a/vala/valaconstant.vala b/vala/valaconstant.vala
new file mode 100644
index 000000000..8f7853520
--- /dev/null
+++ b/vala/valaconstant.vala
@@ -0,0 +1,114 @@
+/* valaconstant.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;
+
+/**
+ * Represents a type member with a constant value.
+ */
+public class Vala.Constant : Member, Lockable {
+ /**
+ * The symbol name of this constant.
+ */
+ public string! name { get; set construct; }
+
+ /**
+ * The data type of this constant.
+ */
+ public TypeReference! type_reference { get; set construct; }
+
+ /**
+ * The value of this constant.
+ */
+ public Expression initializer { get; set; }
+
+ /**
+ * Specifies the accessibility of this constant. Public accessibility
+ * doesn't limit access. Default accessibility limits access to this
+ * program or library. Private accessibility limits access to instances
+ * of the contained type.
+ */
+ public MemberAccessibility access;
+
+ private string cname;
+
+ private bool lock_used = false;
+
+ /**
+ * Creates a new constant.
+ *
+ * @param name constant name
+ * @param type constant type
+ * @param init constant value
+ * @param source reference to source code
+ * @return newly created constant
+ */
+ public Constant (string! _name, TypeReference! type, Expression init, SourceReference source) {
+ name = _name;
+ type_reference = type;
+ initializer = init;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_member (this);
+
+ type_reference.accept (visitor);
+
+ if (initializer != null) {
+ initializer.accept (visitor);
+ }
+
+ visitor.visit_constant (this);
+ }
+
+ /**
+ * Returns the name of this constant as it is used in C code.
+ *
+ * @return the name to be used in C code
+ */
+ public string! get_cname () {
+ if (cname == null) {
+ if (symbol.parent_symbol.node is DataType) {
+ var t = (DataType) symbol.parent_symbol.node;
+ cname = "%s%s".printf (t.get_lower_case_cprefix ().up (), name);
+ } else {
+ var ns = (Namespace) symbol.parent_symbol.node;
+ if (ns == null) {
+ // global constant
+ cname = name;
+ } else {
+ cname = "%s%s".printf (ns.get_lower_case_cprefix ().up (), name);
+ }
+ }
+ }
+ return cname;
+ }
+
+ public bool get_lock_used () {
+ return lock_used;
+ }
+
+ public void set_lock_used (bool used) {
+ lock_used = used;
+ }
+}
diff --git a/vala/valaconstructor.vala b/vala/valaconstructor.vala
new file mode 100644
index 000000000..21c164a73
--- /dev/null
+++ b/vala/valaconstructor.vala
@@ -0,0 +1,67 @@
+/* valaconstructor.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;
+
+/**
+ * Represents a class or instance constructor.
+ */
+public class Vala.Constructor : CodeNode {
+ /**
+ * The body of this constructor.
+ */
+ public Statement body { get; set; }
+
+ private bool _instance = true;
+
+ /**
+ * Specifies whether this is an instance or a class constructor.
+ */
+ public bool instance {
+ get {
+ return _instance;
+ }
+ set {
+ _instance = value;
+ }
+ }
+
+ /**
+ * Creates a new constructor.
+ *
+ * @param source reference to source code
+ * @return newly created constructor
+ */
+ public Constructor (SourceReference source) {
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_constructor (this);
+
+ if (body != null) {
+ body.accept (visitor);
+ }
+
+ visitor.visit_end_constructor (this);
+ }
+}
diff --git a/vala/valacontinuestatement.vala b/vala/valacontinuestatement.vala
new file mode 100644
index 000000000..da0f0d502
--- /dev/null
+++ b/vala/valacontinuestatement.vala
@@ -0,0 +1,42 @@
+/* valacontinuestatement.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;
+
+/**
+ * Represents a continue statement in the source code.
+ */
+public class Vala.ContinueStatement : Statement {
+ /**
+ * Creates a new continue statement.
+ *
+ * @param source reference to source code
+ * @return newly created continue statement
+ */
+ public ContinueStatement (SourceReference source) {
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_continue_statement (this);
+ }
+}
diff --git a/vala/valacreationmethod.vala b/vala/valacreationmethod.vala
new file mode 100644
index 000000000..2113ab1ee
--- /dev/null
+++ b/vala/valacreationmethod.vala
@@ -0,0 +1,67 @@
+/* valacreationmethod.vala
+ *
+ * Copyright (C) 2007 Raffaele Sandrini
+ *
+ * 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:
+ * Raffaele Sandrini <j@bitron.ch>
+ */
+
+using GLib;
+
+/**
+ * Represents a type creation method.
+ */
+public class Vala.CreationMethod : Method {
+ /**
+ * Specifies the number of parameters this creation method sets.
+ */
+ public int n_construction_params { get; set; }
+
+ /**
+ * Creates a new method.
+ *
+ * @param name method name
+ * @param source_reference reference to source code
+ * @return newly created method
+ */
+ public CreationMethod (construct string name, construct SourceReference source_reference = null) {
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_creation_method (this);
+
+ foreach (FormalParameter param in get_parameters()) {
+ param.accept (visitor);
+ }
+
+ if (body != null) {
+ body.accept (visitor);
+ }
+
+ visitor.visit_end_creation_method (this);
+ }
+
+ public override ref string! get_default_cname () {
+ var parent = symbol.parent_symbol.node;
+ assert (parent is DataType);
+ if (name == null) {
+ return "%snew".printf (((DataType) parent).get_lower_case_cprefix ());
+ } else {
+ return "%snew_%s".printf (((DataType) parent).get_lower_case_cprefix (), name);
+ }
+ }
+}
diff --git a/vala/valadatatype.vala b/vala/valadatatype.vala
new file mode 100644
index 000000000..7ea6b433c
--- /dev/null
+++ b/vala/valadatatype.vala
@@ -0,0 +1,310 @@
+/* valatype.vala
+ *
+ * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
+ *
+ * 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>
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+using GLib;
+
+/**
+ * Represents a runtime data type. This data type may be defined in Vala source
+ * code or imported from an external library with a Vala API file.
+ */
+public abstract class Vala.DataType : CodeNode {
+ /**
+ * The symbol name of this data type.
+ */
+ public string name { get; set; }
+
+ /**
+ * Specifies the accessibility of the class. Public accessibility
+ * doesn't limit access. Default accessibility limits access to this
+ * program or library. Protected and private accessibility is not
+ * supported for types.
+ */
+ public MemberAccessibility access;
+
+ /**
+ * The namespace containing this data type.
+ */
+ public weak Namespace @namespace;
+
+ private List<string> cheader_filenames;
+
+ private Pointer pointer_type;
+
+ /* holds the array types of this type; each rank is a separate one */
+ /* FIXME: uses string because int does not work as key yet */
+ private HashTable<string,Array> array_types = new HashTable.full (str_hash, str_equal, g_free, g_object_unref);
+
+ /**
+ * Returns the name of this data type as it is used in C code.
+ *
+ * @return the name to be used in C code
+ */
+ public abstract string get_cname (bool const_type = false);
+
+ /**
+ * Checks whether this data type has value or reference type semantics.
+ *
+ * @return true if this data type has reference type semantics
+ */
+ public virtual bool is_reference_type () {
+ return false;
+ }
+
+ /**
+ * Returns the C function name that duplicates instances of this data
+ * type. The specified C function must accept one argument referencing
+ * the instance of this data type and return a reference to the
+ * duplicate.
+ *
+ * @return the name of the C function if supported or null otherwise
+ */
+ public virtual string get_dup_function () {
+ return null;
+ }
+
+ /**
+ * Returns the C function name that frees instances of this data type.
+ * This is only valid for data types with reference type semantics that
+ * do not support reference counting. The specified C function must
+ * accept one argument pointing to the instance to be freed.
+ *
+ * @return the name of the C function or null if this data type is not a
+ * reference type or if it supports reference counting
+ */
+ public virtual string get_free_function () {
+ return null;
+ }
+
+ /**
+ * Checks whether this data type supports reference counting. This is
+ * only valid for reference types.
+ *
+ * @return true if this data type supports reference counting
+ */
+ public virtual bool is_reference_counting () {
+ return false;
+ }
+
+ /**
+ * Returns the C function name that increments the reference count of
+ * instances of this data type. This is only valid for data types
+ * supporting reference counting. The specified C function must accept
+ * one argument referencing the instance of this data type and return
+ * the reference.
+ *
+ * @return the name of the C function or null if this data type does not
+ * support reference counting
+ */
+ public virtual string get_ref_function () {
+ return null;
+ }
+
+ /**
+ * Returns the C function name that decrements the reference count of
+ * instances of this data type. This is only valid for data types
+ * supporting reference counting. The specified C function must accept
+ * one argument referencing the instance of this data type.
+ *
+ * @return the name of the C function or null if this data type does not
+ * support reference counting
+ */
+ public virtual string get_unref_function () {
+ return null;
+ }
+
+ /**
+ * Returns the C symbol representing the runtime type id for this data
+ * type. The specified symbol must express a registered GType.
+ *
+ * @return the name of the GType name in C code or null if this data
+ * type is not registered with GType
+ */
+ public virtual string get_type_id () {
+ return null;
+ }
+
+ /**
+ * Returns the name of this data type as used in C code marshallers
+ *
+ * @return type name for marshallers
+ */
+ public virtual string get_marshaller_type_name () {
+ return null;
+ }
+
+ /**
+ * Returns the cname of the GValue getter function,
+ */
+ public virtual string get_get_value_function () {
+ return null;
+ }
+
+ /**
+ * Returns the cname of the GValue setter function,
+ */
+ public virtual string get_set_value_function () {
+ return null;
+ }
+
+ /**
+ * Returns the C name of this data type in upper case. Words are
+ * separated by underscores. The upper case C name of the namespace is
+ * prefix of the result.
+ *
+ * @param infix a string to be placed between namespace and data type
+ * name or null
+ * @return the upper case name to be used in C code
+ */
+ public virtual ref string get_upper_case_cname (string infix = null) {
+ return null;
+ }
+
+ /**
+ * Returns the C name of this data type in lower case. Words are
+ * separated by underscores. The lower case C name of the namespace is
+ * prefix of the result.
+ *
+ * @param infix a string to be placed between namespace and data type
+ * name or null
+ * @return the lower case name to be used in C code
+ */
+ public virtual ref string get_lower_case_cname (string infix = null) {
+ return null;
+ }
+
+ /**
+ * Returns the string to be prefixed to members of this data type in
+ * lower case when used in C code.
+ *
+ * @return the lower case prefix to be used in C code
+ */
+ public virtual ref string get_lower_case_cprefix () {
+ return null;
+ }
+
+ /**
+ * Returns the default value for the given type. Returning null means
+ * there is no default value (i.e. not that the default name is NULL).
+ *
+ * @return the name of the default value
+ */
+ public virtual string get_default_value () {
+ return null;
+ }
+
+ /**
+ * Returns a list of C header filenames users of this data type must
+ * include.
+ *
+ * @return list of C header filenames for this data type
+ */
+ public virtual ref List<string> get_cheader_filenames () {
+ if (cheader_filenames == null) {
+ /* default to header filenames of the namespace */
+ foreach (string filename in @namespace.get_cheader_filenames ()) {
+ add_cheader_filename (filename);
+ }
+ }
+ return cheader_filenames.copy ();
+ }
+
+ /**
+ * Adds a filename to the list of C header filenames users of this data
+ * type must include.
+ *
+ * @param filename a C header filename
+ */
+ public void add_cheader_filename (string! filename) {
+ cheader_filenames.append (filename);
+ }
+
+ /**
+ * Returns the pointer type of this data type.
+ *
+ * @return pointer-type for this data type
+ */
+ public Pointer! get_pointer () {
+ if (pointer_type == null) {
+ pointer_type = new Pointer (this, source_reference);
+ /* create a new Symbol */
+ pointer_type.symbol = new Symbol (pointer_type);
+ this.symbol.parent_symbol.add (pointer_type.name, pointer_type.symbol);
+
+ /* link the namespace */
+ pointer_type.@namespace = this.@namespace;
+ }
+
+ return pointer_type;
+ }
+
+ /**
+ * Returns the array type for elements of this data type.
+ *
+ * @param rank the rank the array should be of
+ * @return array type for this data type
+ */
+ public Array! get_array (int rank) {
+ Array array_type = (Array) array_types.lookup (rank.to_string ());
+
+ if (array_type == null) {
+ var new_array_type = new Array (this, rank, source_reference);
+ /* create a new Symbol */
+ new_array_type.symbol = new Symbol (new_array_type);
+ this.symbol.parent_symbol.add (new_array_type.name, new_array_type.symbol);
+
+ /* add internal length field */
+ new_array_type.symbol.add (new_array_type.get_length_field ().name, new_array_type.get_length_field ().symbol);
+ /* add internal resize method */
+ new_array_type.symbol.add (new_array_type.get_resize_method ().name, new_array_type.get_resize_method ().symbol);
+
+ /* link the array type to the same source as the container type */
+ new_array_type.source_reference = this.source_reference;
+ /* link the namespace */
+ new_array_type.@namespace = this.@namespace;
+
+ array_types.insert (rank.to_string (), new_array_type);
+
+ array_type = new_array_type;
+ }
+
+ return array_type;
+ }
+
+ /**
+ * Checks whether this data type is a subtype of the specified data
+ * type.
+ *
+ * @param t a data type
+ * @return true if t is a supertype of this data type, false otherwise
+ */
+ public virtual bool is_subtype_of (DataType! t) {
+ return false;
+ }
+
+ /**
+ * Return the index of the specified type parameter name.
+ */
+ public virtual int get_type_parameter_index (string! name) {
+ return -1;
+ }
+}
diff --git a/vala/valadeclarationstatement.vala b/vala/valadeclarationstatement.vala
new file mode 100644
index 000000000..44b5172d6
--- /dev/null
+++ b/vala/valadeclarationstatement.vala
@@ -0,0 +1,51 @@
+/* valadeclarationstatement.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;
+
+/**
+ * Represents a local variable declaration statement in the source code.
+ */
+public class Vala.DeclarationStatement : Statement {
+ /**
+ * The local variable declaration.
+ */
+ public LocalVariableDeclaration! declaration { get; set construct; }
+
+ /**
+ * Creates a new declaration statement.
+ *
+ * @param decl local variable declaration
+ * @param source reference to source code
+ * @return newly created declaration statement
+ */
+ public DeclarationStatement (LocalVariableDeclaration! decl, SourceReference source) {
+ declaration = decl;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ declaration.accept (visitor);
+
+ visitor.visit_declaration_statement (this);
+ }
+}
diff --git a/vala/valadestructor.vala b/vala/valadestructor.vala
new file mode 100644
index 000000000..726639f1e
--- /dev/null
+++ b/vala/valadestructor.vala
@@ -0,0 +1,67 @@
+/* valadestructor.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;
+
+/**
+ * Represents a class or instance destructor.
+ */
+public class Vala.Destructor : CodeNode {
+ /**
+ * The body of this constructor.
+ */
+ public Statement body { get; set; }
+
+ private bool _instance = true;
+
+ /**
+ * Specifies whether this is an instance or a class destructor.
+ */
+ public bool instance {
+ get {
+ return _instance;
+ }
+ set {
+ _instance = value;
+ }
+ }
+
+ /**
+ * Creates a new destructor.
+ *
+ * @param source reference to source code
+ * @return newly created destructor
+ */
+ public Destructor (SourceReference source) {
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_destructor (this);
+
+ if (body != null) {
+ body.accept (visitor);
+ }
+
+ visitor.visit_end_destructor (this);
+ }
+}
diff --git a/vala/valadostatement.vala b/vala/valadostatement.vala
new file mode 100644
index 000000000..92ea9e99b
--- /dev/null
+++ b/vala/valadostatement.vala
@@ -0,0 +1,78 @@
+/* valadostatement.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;
+
+/**
+ * Represents a do iteration statement in the source code.
+ */
+public class Vala.DoStatement : Statement {
+ /**
+ * Specifies the loop body.
+ */
+ public Statement body { get; set; }
+
+ /**
+ * Specifies the loop condition.
+ */
+ public Expression! condition {
+ get {
+ return _condition;
+ }
+ set construct {
+ _condition = value;
+ _condition.parent_node = this;
+ }
+ }
+
+ private Expression! _condition;
+
+ /**
+ * Creates a new do statement.
+ *
+ * @param cond loop condition
+ * @param body loop body
+ * @param source reference to source code
+ * @return newly created do statement
+ */
+ public DoStatement (Statement! _body, Expression! cond, SourceReference source) {
+ body = _body;
+ condition = cond;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ body.accept (visitor);
+
+ condition.accept (visitor);
+
+ visitor.visit_end_full_expression (condition);
+
+ visitor.visit_do_statement (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (condition == old_node) {
+ condition = (Expression) new_node;
+ }
+ }
+}
diff --git a/vala/valaelementaccess.vala b/vala/valaelementaccess.vala
new file mode 100644
index 000000000..6b2825a95
--- /dev/null
+++ b/vala/valaelementaccess.vala
@@ -0,0 +1,60 @@
+/* valaelementaccess.vala
+ *
+ * Copyright (C) 2006 Raffaele Sandrini
+ *
+ * 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:
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+using GLib;
+
+/**
+ * Represents an array access expression e.g. "a[1,2]".
+ */
+public class Vala.ElementAccess : Expression {
+ /**
+ * Expression representing the container on wich we want to access.
+ */
+ public Expression! container { get; set; }
+
+ /**
+ * Expressions representing the indices we want to access inside the container.
+ */
+ private List<Expression>! indices;
+
+ public void append_index (Expression! index) {
+ indices.append (index);
+ }
+
+ public ref List<weak Expression> get_indices () {
+ return indices.copy ();
+ }
+
+ public ElementAccess (Expression _container, SourceReference source) {
+ container = _container;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ container.accept (visitor);
+ foreach (Expression e in indices) {
+ e.accept (visitor);
+ }
+
+ visitor.visit_element_access (this);
+ }
+}
diff --git a/vala/valaemptystatement.vala b/vala/valaemptystatement.vala
new file mode 100644
index 000000000..9dd75fe1b
--- /dev/null
+++ b/vala/valaemptystatement.vala
@@ -0,0 +1,42 @@
+/* valaemptystatement.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;
+
+/**
+ * An empty statement.
+ */
+public class Vala.EmptyStatement : Statement {
+ /**
+ * Creates a new empty statement.
+ *
+ * @param source reference to source code
+ * @return newly created empty statement
+ */
+ public EmptyStatement (SourceReference source) {
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_empty_statement (this);
+ }
+}
diff --git a/vala/valaenum.vala b/vala/valaenum.vala
new file mode 100644
index 000000000..a759c00cd
--- /dev/null
+++ b/vala/valaenum.vala
@@ -0,0 +1,152 @@
+/* valaenum.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;
+
+/**
+ * Represents an enum declaration in the source code.
+ */
+public class Vala.Enum : DataType {
+ private List<EnumValue> values;
+ private string cname;
+ private string cprefix;
+
+ /**
+ * Creates a new enum.
+ *
+ * @param name type name
+ * @param source reference to source code
+ * @return newly created enum
+ */
+ public Enum (string! _name, SourceReference source = null) {
+ name = _name;
+ source_reference = source;
+ }
+
+ /**
+ * Appends the specified enum value to the list of values.
+ *
+ * @param value an enum value
+ */
+ public void add_value (EnumValue! value) {
+ values.append (value);
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_enum (this);
+
+ foreach (EnumValue value in values) {
+ value.accept (visitor);
+ }
+
+ visitor.visit_end_enum (this);
+ }
+
+ public override string get_cname (bool const_type = false) {
+ if (cname == null) {
+ cname = "%s%s".printf (@namespace.get_cprefix (), name);
+ }
+ return cname;
+ }
+
+ public override ref string get_upper_case_cname (string infix) {
+ return "%s%s".printf (@namespace.get_lower_case_cprefix (), Namespace.camel_case_to_lower_case (name)).up ();
+ }
+
+ public override bool is_reference_type () {
+ return false;
+ }
+
+ private void set_cname (string! cname) {
+ this.cname = cname;
+ }
+
+ /**
+ * Returns the string to be prepended to the name of members of this
+ * enum when used in C code.
+ *
+ * @return the prefix to be used in C code
+ */
+ public string! get_cprefix () {
+ if (cprefix == null) {
+ cprefix = "%s_".printf (get_upper_case_cname (null));
+ }
+ return cprefix;
+ }
+
+ /**
+ * Sets the string to be prepended to the name of members of this enum
+ * when used in C code.
+ *
+ * @param cprefix the prefix to be used in C code
+ */
+ public void set_cprefix (string! cprefix) {
+ this.cprefix = cprefix;
+ }
+
+ private void process_ccode_attribute (Attribute! a) {
+ if (a.has_argument ("cname")) {
+ set_cname (a.get_string ("cname"));
+ }
+ if (a.has_argument ("cprefix")) {
+ set_cprefix (a.get_string ("cprefix"));
+ }
+ if (a.has_argument ("cheader_filename")) {
+ var val = a.get_string ("cheader_filename");
+ foreach (string filename in val.split (",")) {
+ add_cheader_filename (filename);
+ }
+ }
+ }
+
+ /**
+ * Process all associated attributes.
+ */
+ public void process_attributes () {
+ foreach (Attribute a in attributes) {
+ if (a.name == "CCode") {
+ process_ccode_attribute (a);
+ }
+ }
+ }
+
+ public override string get_type_id () {
+ // FIXME: use GType-registered enums
+ return "G_TYPE_INT";
+ }
+
+ public override string get_marshaller_type_name () {
+ return "ENUM";
+ }
+
+ public override string get_get_value_function () {
+ return "g_value_get_enum";
+ }
+
+ public override string get_set_value_function () {
+ return "g_value_set_enum";
+ }
+
+ public override string get_default_value () {
+ return "0";
+ }
+}
diff --git a/vala/valaenumvalue.vala b/vala/valaenumvalue.vala
new file mode 100644
index 000000000..740983ef2
--- /dev/null
+++ b/vala/valaenumvalue.vala
@@ -0,0 +1,79 @@
+/* valaenumvalue.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;
+
+/**
+ * Represents an enum member in the source code.
+ */
+public class Vala.EnumValue : CodeNode {
+ /**
+ * The symbol name of this enum value.
+ */
+ public string! name { get; set construct; }
+
+ /**
+ * Specifies the numerical representation of this enum value.
+ */
+ public Expression value { get; set; }
+
+ private string cname;
+
+ /**
+ * Creates a new enum value.
+ *
+ * @param name enum value name
+ * @return newly created enum value
+ */
+ public EnumValue (string! _name) {
+ name = _name;
+ }
+
+ /**
+ * Creates a new enum value with the specified numerical representation.
+ *
+ * @param name enum value name
+ * @param value numerical representation
+ * @return newly created enum value
+ */
+ public EnumValue.with_value (string! _name, Expression _value) {
+ name = _name;
+ value = _value;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_enum_value (this);
+ }
+
+ /**
+ * Returns the name of this enum value as it is used in C code.
+ *
+ * @return the name to be used in C code
+ */
+ public string! get_cname () {
+ if (cname == null) {
+ var en = (Enum) symbol.parent_symbol.node;
+ cname = "%s%s".printf (en.get_cprefix (), name);
+ }
+ return cname;
+ }
+}
diff --git a/vala/valaexpression.vala b/vala/valaexpression.vala
new file mode 100644
index 000000000..38a8a9f72
--- /dev/null
+++ b/vala/valaexpression.vala
@@ -0,0 +1,76 @@
+/* valaexpression.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * Base class for all code nodes that might be used as an expression.
+ */
+public abstract class Vala.Expression : CodeNode {
+ /**
+ * The static type of this expression.
+ *
+ * The semantic analyzer computes this value.
+ */
+ public TypeReference static_type { get; set; }
+
+ /*
+ * The static type this expression is expected to have.
+ *
+ * The semantic analyzer computes this value, lambda expressions use it.
+ */
+ public TypeReference expected_type { get; set; }
+
+ /**
+ * The symbol this expression refers to.
+ */
+ public Symbol symbol_reference { get; set; }
+
+ /**
+ * Specifies that this expression transfers ownership without a receiver
+ * being present.
+ *
+ * The memory manager computes this value, the code generator uses it.
+ */
+ public bool ref_leaked { get; set; }
+
+ /**
+ * Specifies that this expression is expected to transfer ownership but
+ * doesn't.
+ *
+ * The memory manager computes this value, the code generator uses it.
+ */
+ public bool ref_missing { get; set; }
+
+ /**
+ * Specifies that this expression successfully transfers ownership.
+ */
+ public bool ref_sink { get; set; }
+
+ /**
+ * Contains all temporary variables this expression requires for
+ * execution.
+ *
+ * The code generator sets and uses them for memory management.
+ */
+ public List<VariableDeclarator> temp_vars;
+}
diff --git a/vala/valaexpressionstatement.vala b/vala/valaexpressionstatement.vala
new file mode 100644
index 000000000..472ec195f
--- /dev/null
+++ b/vala/valaexpressionstatement.vala
@@ -0,0 +1,85 @@
+/* valaexpressionstatement.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;
+
+/**
+ * A code statement that evaluates a given expression. The value computed by the
+ * expression, if any, is discarded.
+ */
+public class Vala.ExpressionStatement : Statement {
+ /**
+ * Specifies the expression to evaluate.
+ */
+ public Expression! expression {
+ get {
+ return _expression;
+ }
+ set construct {
+ _expression = value;
+ _expression.parent_node = this;
+ }
+ }
+
+ private Expression! _expression;
+
+ /**
+ * Creates a new expression statement.
+ *
+ * @param expr expression to evaluate
+ * @param source reference to source code
+ * @return newly created expression statement
+ */
+ public ExpressionStatement (Expression! expr, SourceReference source = null) {
+ expression = expr;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ expression.accept (visitor);
+
+ visitor.visit_expression_statement (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (expression == old_node) {
+ expression = (Expression) new_node;
+ }
+ }
+
+ public override int get_number_of_set_construction_parameters () {
+ if (expression is Assignment) {
+ var assign = (Assignment) expression;
+ if (assign.left is MemberAccess) {
+ var ma = (MemberAccess) assign.left;
+ if (ma.symbol_reference != null) {
+ if (ma.symbol_reference.node is Property) {
+ var prop = (Property) ma.symbol_reference.node;
+ return 1;
+ }
+ }
+ }
+ }
+
+ return -1;
+ }
+}
diff --git a/vala/valafield.vala b/vala/valafield.vala
new file mode 100644
index 000000000..884de7545
--- /dev/null
+++ b/vala/valafield.vala
@@ -0,0 +1,173 @@
+/* valafield.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;
+
+/**
+ * Represents a type or namespace field.
+ */
+public class Vala.Field : Member, Invokable, Lockable {
+ /**
+ * The symbol name of this field.
+ */
+ public string! name { get; set construct; }
+
+ /**
+ * The data type of this field.
+ */
+ public TypeReference! type_reference { get; set construct; }
+
+ /**
+ * Specifies the expression to be used to initialize this field.
+ */
+ public Expression initializer { get; set; }
+
+ /**
+ * Specifies the accessibility of this field. Public accessibility
+ * doesn't limit access. Default accessibility limits access to this
+ * program or library. Private accessibility limits access to instances
+ * of the contained type.
+ */
+ public MemberAccessibility access;
+
+ /**
+ * Specifies whether this field may only be accessed with an instance of
+ * the contained type.
+ */
+ public bool instance {
+ get {
+ return _instance;
+ }
+ set {
+ _instance = value;
+ }
+ }
+
+ /**
+ * Specifies whether an array length field should implicitly be created
+ * if the field type is an array.
+ */
+ public bool no_array_length { get; set; }
+
+ private string cname;
+ private bool _instance = true;
+
+ private bool lock_used = false;
+
+ /**
+ * Creates a new field.
+ *
+ * @param name field name
+ * @param type field type
+ * @param init initializer expression
+ * @param source reference to source code
+ * @return newly created field
+ */
+ public Field (string! _name, TypeReference! type, Expression init, SourceReference source) {
+ name = _name;
+ type_reference = type;
+ initializer = init;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_member (this);
+
+ type_reference.accept (visitor);
+
+ if (initializer != null) {
+ initializer.accept (visitor);
+ }
+
+ visitor.visit_field (this);
+ }
+
+ /**
+ * Returns the name of this field as it is used in C code.
+ *
+ * @return the name to be used in C code
+ */
+ public string! get_cname () {
+ if (cname == null) {
+ if (!instance && symbol.parent_symbol.node is DataType) {
+ var t = (DataType) symbol.parent_symbol.node;
+ cname = "%s_%s".printf (t.get_lower_case_cname (null), name);
+ } else {
+ cname = name;
+ }
+ }
+ return cname;
+ }
+
+ private void set_cname (string! cname) {
+ this.cname = cname;
+ }
+
+ private void process_ccode_attribute (Attribute! a) {
+ if (a.has_argument ("cname")) {
+ set_cname (a.get_string ("cname"));
+ }
+ }
+
+ /**
+ * Process all associated attributes.
+ */
+ public void process_attributes () {
+ foreach (Attribute a in attributes) {
+ if (a.name == "CCode") {
+ process_ccode_attribute (a);
+ } else if (a.name == "NoArrayLength") {
+ no_array_length = true;
+ }
+ }
+ }
+
+ public ref List<weak FormalParameter> get_parameters () {
+ if (!is_invokable ()) {
+ return null;
+ }
+
+ var cb = (Callback) type_reference.data_type;
+ return cb.get_parameters ();
+ }
+
+ public TypeReference get_return_type () {
+ if (!is_invokable ()) {
+ return null;
+ }
+
+ var cb = (Callback) type_reference.data_type;
+ return cb.return_type;
+ }
+
+ public bool is_invokable () {
+ return (type_reference.data_type is Callback);
+ }
+
+ public bool get_lock_used () {
+ return lock_used;
+ }
+
+ public void set_lock_used (bool used) {
+ lock_used = used;
+ }
+}
diff --git a/vala/valaflags.vala b/vala/valaflags.vala
new file mode 100644
index 000000000..d47cb8b82
--- /dev/null
+++ b/vala/valaflags.vala
@@ -0,0 +1,150 @@
+/* valaflags.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * Represents a flags declaration in the source code.
+ */
+public class Vala.Flags : DataType {
+ private List<FlagsValue> values;
+ private string cname;
+ private string cprefix;
+
+ /**
+ * Creates a new flags.
+ *
+ * @param name type name
+ * @param source reference to source code
+ * @return newly created flags
+ */
+ public Flags (construct string! name, construct SourceReference source_reference = null) {
+ }
+
+ /**
+ * Appends the specified flags value to the list of values.
+ *
+ * @param value a flags value
+ */
+ public void add_value (FlagsValue! value) {
+ values.append (value);
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_flags (this);
+
+ foreach (FlagsValue value in values) {
+ value.accept (visitor);
+ }
+
+ visitor.visit_end_flags (this);
+ }
+
+ public override string get_cname (bool const_type = false) {
+ if (cname == null) {
+ cname = "%s%s".printf (@namespace.get_cprefix (), name);
+ }
+ return cname;
+ }
+
+ public override ref string get_upper_case_cname (string infix) {
+ return "%s%s".printf (@namespace.get_lower_case_cprefix (), Namespace.camel_case_to_lower_case (name)).up ();
+ }
+
+ public override bool is_reference_type () {
+ return false;
+ }
+
+ private void set_cname (string! cname) {
+ this.cname = cname;
+ }
+
+ /**
+ * Returns the string to be prepended to the name of members of this
+ * enum when used in C code.
+ *
+ * @return the prefix to be used in C code
+ */
+ public string! get_cprefix () {
+ if (cprefix == null) {
+ cprefix = "%s_".printf (get_upper_case_cname (null));
+ }
+ return cprefix;
+ }
+
+ /**
+ * Sets the string to be prepended to the name of members of this enum
+ * when used in C code.
+ *
+ * @param cprefix the prefix to be used in C code
+ */
+ public void set_cprefix (string! cprefix) {
+ this.cprefix = cprefix;
+ }
+
+ private void process_ccode_attribute (Attribute! a) {
+ if (a.has_argument ("cname")) {
+ set_cname (a.get_string ("cname"));
+ }
+ if (a.has_argument ("cprefix")) {
+ set_cprefix (a.get_string ("cprefix"));
+ }
+ if (a.has_argument ("cheader_filename")) {
+ var val = a.get_string ("cheader_filename");
+ foreach (string filename in val.split (",")) {
+ add_cheader_filename (filename);
+ }
+ }
+ }
+
+ /**
+ * Process all associated attributes.
+ */
+ public void process_attributes () {
+ foreach (Attribute a in attributes) {
+ if (a.name == "CCode") {
+ process_ccode_attribute (a);
+ }
+ }
+ }
+
+ public override string get_type_id () {
+ // FIXME: use GType-registered flags
+ return "G_TYPE_INT";
+ }
+
+ public override string get_marshaller_type_name () {
+ return "FLAGS";
+ }
+
+ public override string get_get_value_function () {
+ return "g_value_get_flags";
+ }
+
+ public override string get_set_value_function () {
+ return "g_value_set_flags";
+ }
+
+ public override string get_default_value () {
+ return "0";
+ }
+}
diff --git a/vala/valaflagsvalue.vala b/vala/valaflagsvalue.vala
new file mode 100644
index 000000000..232bc322d
--- /dev/null
+++ b/vala/valaflagsvalue.vala
@@ -0,0 +1,80 @@
+/* valaflagsvalue.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;
+
+/**
+ * Represents a flags member in the source code.
+ */
+public class Vala.FlagsValue : CodeNode {
+ /**
+ * The symbol name of this flags value.
+ */
+ public string! name { get; set construct; }
+
+ /**
+ * Specifies the numerical representation of this flags value.
+ */
+ public Expression value { get; set; }
+
+ private string cname;
+
+ /**
+ * Creates a new flags value.
+ *
+ * @param name flags value name
+ * @return newly created flags value
+ */
+ public FlagsValue (string! _name) {
+ name = _name;
+ }
+
+ /**
+ * Creates a new flags value with the specified numerical
+ * representation.
+ *
+ * @param name flags value name
+ * @param value numerical representation
+ * @return newly created flags value
+ */
+ public FlagsValue.with_value (string! _name, Expression _value) {
+ name = _name;
+ value = _value;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_flags_value (this);
+ }
+
+ /**
+ * Returns the name of this flags value as it is used in C code.
+ *
+ * @return the name to be used in C code
+ */
+ public string! get_cname () {
+ if (cname == null) {
+ var fl = (Flags) symbol.parent_symbol.node;
+ cname = "%s_%s".printf (fl.get_upper_case_cname (null), name);
+ }
+ return cname;
+ }
+}
diff --git a/vala/valaforeachstatement.vala b/vala/valaforeachstatement.vala
new file mode 100644
index 000000000..f4ec9a962
--- /dev/null
+++ b/vala/valaforeachstatement.vala
@@ -0,0 +1,97 @@
+/* valaforeachstatement.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;
+
+/**
+ * Represents a foreach statement in the source code. Foreach statements iterate
+ * over the elements of a collection.
+ */
+public class Vala.ForeachStatement : Statement {
+ /**
+ * Specifies the element type.
+ */
+ public TypeReference! type_reference { get; set construct; }
+
+ /**
+ * Specifies the element variable name.
+ */
+ public string! variable_name { get; set construct; }
+
+ /**
+ * Specifies the container.
+ */
+ public Expression! collection {
+ get {
+ return _collection;
+ }
+ set construct {
+ _collection = value;
+ _collection.parent_node = this;
+ }
+ }
+
+ /**
+ * Specifies the loop body.
+ */
+ public Statement body { get; set; }
+
+ /**
+ * Specifies the declarator for the generated element variable.
+ */
+ public VariableDeclarator variable_declarator { get; set; }
+
+ private Expression! _collection;
+
+ /**
+ * Creates a new foreach statement.
+ *
+ * @param type element type
+ * @param id element variable name
+ * @param col loop body
+ * @param source reference to source code
+ * @return newly created foreach statement
+ */
+ public ForeachStatement (TypeReference! type, string! id, Expression! col, Statement _body, SourceReference source) {
+ type_reference = type;
+ variable_name = id;
+ collection = col;
+ body = _body;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_foreach_statement (this);
+
+ type_reference.accept (visitor);
+ collection.accept (visitor);
+ body.accept (visitor);
+
+ visitor.visit_end_foreach_statement (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (collection == old_node) {
+ collection = (Expression) new_node;
+ }
+ }
+}
diff --git a/vala/valaformalparameter.vala b/vala/valaformalparameter.vala
new file mode 100644
index 000000000..4b4d3cf71
--- /dev/null
+++ b/vala/valaformalparameter.vala
@@ -0,0 +1,120 @@
+/* valaformalparameter.vala
+ *
+ * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
+ *
+ * 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>
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+using GLib;
+
+/**
+ * Represents a formal parameter in method and callback signatures.
+ */
+public class Vala.FormalParameter : CodeNode, Invokable {
+ /**
+ * The parameter name.
+ */
+ public string! name { get; set construct; }
+
+ /**
+ * The parameter type.
+ */
+ public TypeReference type_reference { get; set; }
+
+ /**
+ * Specifies whether the methods accepts an indefinite number of
+ * parameters.
+ */
+ public bool ellipsis { get; set; }
+
+ /**
+ * Specifies the expression used when the caller doesn't supply an
+ * argument for this parameter.
+ */
+ public Expression default_expression { get; set; }
+
+ /**
+ * Specifies whether the array length should implicitly be passed
+ * if the parameter type is an array.
+ */
+ public bool no_array_length { get; set; }
+
+ /**
+ * Specifies whether this parameter holds a value to be assigned to a
+ * construct property. This is only allowed in CreationMethod headers.
+ */
+ public bool construct_parameter { get; set; }
+
+ /**
+ * Creates a new formal parameter.
+ *
+ * @param name parameter name
+ * @param type parameter type
+ * @param source reference to source code
+ * @return newly created formal parameter
+ */
+ public FormalParameter (string! _name, TypeReference type, SourceReference source = null) {
+ name = _name;
+ type_reference = type;
+ source_reference = source;
+ }
+
+ /**
+ * Creates a new ellipsis parameter representing an indefinite number of
+ * parameters.
+ */
+ public FormalParameter.with_ellipsis (SourceReference source = null) {
+ ellipsis = true;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ if (!ellipsis) {
+ type_reference.accept (visitor);
+
+ if (default_expression != null) {
+ default_expression.accept (visitor);
+ }
+ }
+
+ visitor.visit_formal_parameter (this);
+ }
+
+ public ref List<weak FormalParameter> get_parameters () {
+ if (!is_invokable ()) {
+ return null;
+ }
+
+ var cb = (Callback) type_reference.data_type;
+ return cb.get_parameters ();
+ }
+
+ public TypeReference get_return_type () {
+ if (!is_invokable ()) {
+ return null;
+ }
+
+ var cb = (Callback) type_reference.data_type;
+ return cb.return_type;
+ }
+
+ public bool is_invokable () {
+ return (type_reference.data_type is Callback);
+ }
+}
diff --git a/vala/valaforstatement.vala b/vala/valaforstatement.vala
new file mode 100644
index 000000000..e7d7238de
--- /dev/null
+++ b/vala/valaforstatement.vala
@@ -0,0 +1,150 @@
+/* valaforstatement.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * Represents a for iteration statement in the source code.
+ */
+public class Vala.ForStatement : Statement {
+ /**
+ * Specifies the loop condition.
+ */
+ public Expression! condition {
+ get {
+ return _condition;
+ }
+ set construct {
+ _condition = value;
+ _condition.parent_node = this;
+ }
+ }
+
+ /**
+ * Specifies the loop body.
+ */
+ public Statement body { get; set; }
+
+ private List<Expression> initializer;
+ private List<Expression> iterator;
+
+ private Expression! _condition;
+
+ /**
+ * Creates a new for statement.
+ *
+ * @param cond loop condition
+ * @param body loop body
+ * @param source reference to source code
+ * @return newly created for statement
+ */
+ public ForStatement (Expression cond, Statement _body, SourceReference source) {
+ condition = cond;
+ body = _body;
+ source_reference = source;
+ }
+
+ /**
+ * Appends the specified expression to the list of initializers.
+ *
+ * @param init an initializer expression
+ */
+ public void add_initializer (Expression! init) {
+ init.parent_node = this;
+ initializer.append (init);
+ }
+
+ /**
+ * Returns a copy of the list of initializers.
+ *
+ * @return initializer list
+ */
+ public ref List<weak Expression> get_initializer () {
+ return initializer.copy ();
+ }
+
+ /**
+ * Appends the specified expression to the iterator.
+ *
+ * @param iter an iterator expression
+ */
+ public void add_iterator (Expression! iter) {
+ iter.parent_node = this;
+ iterator.append (iter);
+ }
+
+ /**
+ * Returns a copy of the iterator.
+ *
+ * @return iterator
+ */
+ public ref List<weak Expression> get_iterator () {
+ return iterator.copy ();
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ foreach (Expression init_expr in initializer) {
+ init_expr.accept (visitor);
+ visitor.visit_end_full_expression (init_expr);
+ }
+
+ condition.accept (visitor);
+
+ visitor.visit_end_full_expression (condition);
+
+ foreach (Expression it_expr in iterator) {
+ it_expr.accept (visitor);
+ visitor.visit_end_full_expression (it_expr);
+ }
+
+ body.accept (visitor);
+
+ visitor.visit_for_statement (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ weak List<Expression> iter;
+
+ if (condition == old_node) {
+ condition = (Expression) new_node;
+ return;
+ }
+
+ for (iter = initializer; iter != null; iter = iter.next) {
+ if (iter.data == old_node) {
+ weak List<Expression> silbling = iter.next;
+ initializer.delete_link (iter);
+ initializer.insert_before (silbling, new_node);
+ return;
+ }
+ }
+
+ for (iter = iterator; iter != null; iter = iter.next) {
+ if (iter.data == old_node) {
+ weak List<Expression> silbling = iter.next;
+ iterator.delete_link (iter);
+ iterator.insert_before (silbling, new_node);
+ return;
+ }
+ }
+ }
+}
diff --git a/vala/valaifstatement.vala b/vala/valaifstatement.vala
new file mode 100644
index 000000000..2912db849
--- /dev/null
+++ b/vala/valaifstatement.vala
@@ -0,0 +1,87 @@
+/* valaifstatement.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;
+
+/**
+ * Represents an if selection statement in the source code.
+ */
+public class Vala.IfStatement : Statement {
+ /**
+ * The boolean condition to evaluate.
+ */
+ public Expression! condition {
+ get {
+ return _condition;
+ }
+ set construct {
+ _condition = value;
+ _condition.parent_node = this;
+ }
+ }
+
+ /**
+ * The statement to be evaluated if the condition holds.
+ */
+ public Block! true_statement { get; set construct; }
+
+ /**
+ * The optional statement to be evaluated if the condition doesn't hold.
+ */
+ public Block false_statement { get; set construct; }
+
+ private Expression! _condition;
+
+ /**
+ * Creates a new if statement.
+ *
+ * @param cond a boolean condition
+ * @param true_stmt statement to be evaluated if condition is true
+ * @param false_stmt statement to be evaluated if condition is false
+ * @return newly created if statement
+ */
+ public IfStatement (Expression! cond, Block! true_stmt, Block false_stmt, SourceReference source) {
+ condition = cond;
+ true_statement = true_stmt;
+ false_statement = false_stmt;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ condition.accept (visitor);
+
+ visitor.visit_end_full_expression (condition);
+
+ true_statement.accept (visitor);
+ if (false_statement != null) {
+ false_statement.accept (visitor);
+ }
+
+ visitor.visit_if_statement (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (condition == old_node) {
+ condition = (Expression) new_node;
+ }
+ }
+}
diff --git a/vala/valainitializerlist.vala b/vala/valainitializerlist.vala
new file mode 100644
index 000000000..b20528bc4
--- /dev/null
+++ b/vala/valainitializerlist.vala
@@ -0,0 +1,68 @@
+/* valainitializerlist.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;
+
+/**
+ * Represents an array or struct initializer list in the source code.
+ */
+public class Vala.InitializerList : Expression {
+ private List<Expression> initializers;
+
+ /**
+ * Appends the specified expression to this initializer list.
+ *
+ * @param expr an expression
+ */
+ public void append (Expression! expr) {
+ initializers.append (expr);
+ }
+
+ /**
+ * Returns a copy of the expression list.
+ *
+ * @return expression list
+ */
+ public ref List<weak Expression> get_initializers () {
+ return initializers.copy ();
+ }
+
+ /**
+ * Creates a new initializer list.
+ *
+ * @param source reference to source code
+ * @return newly created initializer list
+ */
+ public InitializerList (SourceReference source) {
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_initializer_list (this);
+
+ foreach (Expression expr in initializers) {
+ expr.accept (visitor);
+ }
+
+ visitor.visit_end_initializer_list (this);
+ }
+}
diff --git a/vala/valainstancecast.vala b/vala/valainstancecast.vala
new file mode 100644
index 000000000..f154ce99f
--- /dev/null
+++ b/vala/valainstancecast.vala
@@ -0,0 +1,58 @@
+/* valainstancecast.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;
+
+/**
+ * Represents a runtime checked object instance cast expression in the C code.
+ */
+public class Vala.InstanceCast : CCodeFunctionCall {
+ /**
+ * The target type.
+ */
+ public DataType! type_reference { get; set construct; }
+
+ /**
+ * The expression to be cast.
+ */
+ public CCodeExpression! inner { get; set construct; }
+
+ /**
+ * Creates a new instance cast expression.
+ *
+ * @param expr an expression
+ * @param type the target type
+ * @return newly created instance cast expression
+ */
+ public InstanceCast (CCodeExpression! expr, DataType! type) {
+ inner = expr;
+ type_reference = type;
+ }
+
+ construct {
+ call = new CCodeIdentifier (type_reference.get_upper_case_cname (null));
+ add_argument ((CCodeExpression) inner);
+ }
+}
+
+
+
diff --git a/vala/valaintegerliteral.vala b/vala/valaintegerliteral.vala
new file mode 100644
index 000000000..671381f11
--- /dev/null
+++ b/vala/valaintegerliteral.vala
@@ -0,0 +1,103 @@
+/* valaintegerliteral.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;
+
+/**
+ * Represents an integer literal in the source code.
+ */
+public class Vala.IntegerLiteral : Literal {
+ /**
+ * The literal value.
+ */
+ public string! value { get; set; }
+
+ /**
+ * Creates a new integer literal.
+ *
+ * @param i literal value
+ * @param source reference to source code
+ * @return newly created integer literal
+ */
+ public IntegerLiteral (string! i, SourceReference source = null) {
+ value = i;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_integer_literal (this);
+ }
+
+ public override ref string! to_string () {
+ return value;
+ }
+
+ /**
+ * Returns the type name of the value this literal represents.
+ *
+ * @return the name of literal type
+ */
+ public string! get_type_name () {
+ string number = value;
+
+ int l = 0;
+ while (number.has_suffix ("L")) {
+ l++;
+ number = number.ndup (number.size () - 1);
+ }
+
+ bool u = false;
+ if (number.has_suffix ("U")) {
+ u = true;
+ number = number.ndup (number.size () - 1);
+ }
+
+ int64 n = number.to_int64 ();
+ if (!u && n > 0x7fffffff) {
+ // value doesn't fit into signed 32-bit
+ l = 2;
+ } else if (u && n > 0xffffffff) {
+ // value doesn't fit into unsigned 32-bit
+ l = 2;
+ }
+
+ if (l == 0) {
+ if (u) {
+ return "uint";
+ } else {
+ return "int";
+ }
+ } else if (l == 1) {
+ if (u) {
+ return "ulong";
+ } else {
+ return "long";
+ }
+ } else {
+ if (u) {
+ return "uint64";
+ } else {
+ return "int64";
+ }
+ }
+ }
+}
diff --git a/vala/valainterface.vala b/vala/valainterface.vala
new file mode 100644
index 000000000..a9abea8f4
--- /dev/null
+++ b/vala/valainterface.vala
@@ -0,0 +1,309 @@
+/* valainterface.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * Represents a class declaration in the source code.
+ */
+public class Vala.Interface : DataType {
+ /**
+ * Specifies whether this interface is static. Static interfaces are not
+ * available at run-time. They can be implemented by structs.
+ */
+ public bool is_static { get; set; }
+
+ private List<TypeParameter> type_parameters;
+
+ private List<TypeReference> prerequisites;
+
+ private List<Method> methods;
+ private List<Property> properties;
+ private List<Signal> signals;
+
+ private string cname;
+ private string lower_case_csuffix;
+ private string type_cname;
+ private string type_id;
+
+ /**
+ * Creates a new interface.
+ *
+ * @param name type name
+ * @param source reference to source code
+ * @return newly created interface
+ */
+ public Interface (string! _name, SourceReference source = null) {
+ name = _name;
+ source_reference = source;
+ }
+
+ /**
+ * Appends the specified parameter to the list of type parameters.
+ *
+ * @param p a type parameter
+ */
+ public void add_type_parameter (TypeParameter! p) {
+ type_parameters.append (p);
+ p.type = this;
+ }
+
+ /**
+ * Adds the specified interface or class to the list of prerequisites of
+ * this interface.
+ *
+ * @param type an interface or class reference
+ */
+ public void add_prerequisite (TypeReference! type) {
+ prerequisites.append (type);
+ }
+
+ /**
+ * Returns a copy of the base type list.
+ *
+ * @return list of base types
+ */
+ public ref List<weak TypeReference> get_prerequisites () {
+ return prerequisites.copy ();
+ }
+
+ /**
+ * Adds the specified method as a member to this interface.
+ *
+ * @param m a method
+ */
+ public void add_method (Method! m) {
+ methods.append (m);
+ }
+
+ /**
+ * Returns a copy of the list of methods.
+ *
+ * @return list of methods
+ */
+ public ref List<weak Method> get_methods () {
+ return methods.copy ();
+ }
+
+ /**
+ * Adds the specified property as a member to this interface.
+ *
+ * @param prop a property
+ */
+ public void add_property (Property! prop) {
+ properties.append (prop);
+ }
+
+ /**
+ * Returns a copy of the list of properties.
+ *
+ * @return list of properties
+ */
+ public ref List<weak Property> get_properties () {
+ return properties.copy ();
+ }
+
+ /**
+ * Adds the specified signal as a member to this interface.
+ *
+ * @param sig a signal
+ */
+ public void add_signal (Signal! sig) {
+ signals.append (sig);
+ }
+
+ /**
+ * Returns a copy of the list of signals.
+ *
+ * @return list of signals
+ */
+ public ref List<weak Signal> get_signals () {
+ return signals.copy ();
+ }
+
+ public override string get_cname (bool const_type = false) {
+ if (cname == null) {
+ cname = "%s%s".printf (@namespace.get_cprefix (), name);
+ }
+ return cname;
+ }
+
+ /**
+ * Returns the string to be prepended to the name of members of this
+ * interface when used in C code.
+ *
+ * @return the suffix to be used in C code
+ */
+ public string! get_lower_case_csuffix () {
+ if (lower_case_csuffix == null) {
+ lower_case_csuffix = Namespace.camel_case_to_lower_case (name);
+ }
+ return lower_case_csuffix;
+ }
+
+ /**
+ * Sets the string to be prepended to the name of members of this
+ * interface when used in C code.
+ *
+ * @param csuffix the suffix to be used in C code
+ */
+ public void set_lower_case_csuffix (string! csuffix) {
+ this.lower_case_csuffix = csuffix;
+ }
+
+ public override ref string get_lower_case_cname (string infix) {
+ if (infix == null) {
+ infix = "";
+ }
+ return "%s%s%s".printf (@namespace.get_lower_case_cprefix (), infix, get_lower_case_csuffix ());
+ }
+
+ public override ref string get_lower_case_cprefix () {
+ return "%s_".printf (get_lower_case_cname (null));
+ }
+
+ public override ref string get_upper_case_cname (string infix) {
+ return get_lower_case_cname (infix).up ();
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_interface (this);
+
+ foreach (TypeReference type in prerequisites) {
+ type.accept (visitor);
+ }
+
+ foreach (TypeParameter p in type_parameters) {
+ p.accept (visitor);
+ }
+
+ foreach (Method m in methods) {
+ m.accept (visitor);
+ }
+
+ foreach (Property prop in properties) {
+ prop.accept (visitor);
+ }
+
+ foreach (Signal sig in signals) {
+ sig.accept (visitor);
+ }
+
+ visitor.visit_end_interface (this);
+ }
+
+ public override bool is_reference_type () {
+ return true;
+ }
+
+ public override bool is_reference_counting () {
+ return true;
+ }
+
+ public override string get_ref_function () {
+ return "g_object_ref";
+ }
+
+ public override string get_unref_function () {
+ return "g_object_unref";
+ }
+
+ public override bool is_subtype_of (DataType! t) {
+ foreach (TypeReference prerequisite in prerequisites) {
+ if (prerequisite.data_type == t ||
+ prerequisite.data_type.is_subtype_of (t)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private void process_ccode_attribute (Attribute! a) {
+ if (a.has_argument ("type_cname")) {
+ set_type_cname (a.get_string ("type_cname"));
+ }
+ }
+
+ /**
+ * Process all associated attributes.
+ */
+ public void process_attributes () {
+ foreach (Attribute a in attributes) {
+ if (a.name == "CCode") {
+ process_ccode_attribute (a);
+ }
+ }
+ }
+
+ /**
+ * Returns the name of the type struct as it is used in C code.
+ *
+ * @return the type struct name to be used in C code
+ */
+ public string get_type_cname () {
+ if (type_cname == null) {
+ type_cname = "%sIface".printf (get_cname ());
+ }
+ return type_cname;
+ }
+
+ /**
+ * Sets the name of the type struct as it is used in C code.
+ *
+ * @param type_cname the type struct name to be used in C code
+ */
+ public void set_type_cname (string! type_cname) {
+ this.type_cname = type_cname;
+ }
+
+ public override string get_marshaller_type_name () {
+ return "OBJECT";
+ }
+
+ public override string get_get_value_function () {
+ return "g_value_get_object";
+ }
+
+ public override string get_set_value_function () {
+ return "g_value_set_object";
+ }
+
+ public override string get_type_id () {
+ if (type_id == null) {
+ type_id = get_upper_case_cname ("TYPE_");
+ }
+
+ return type_id;
+ }
+
+ public override int get_type_parameter_index (string! name) {
+ int i = 0;
+ foreach (TypeParameter parameter in type_parameters) {
+ if (parameter.name == name) {
+ return i;
+ }
+ i++;
+ }
+ return -1;
+ }
+}
diff --git a/vala/valainterfaceregisterfunction.vala b/vala/valainterfaceregisterfunction.vala
new file mode 100644
index 000000000..7b9a94d07
--- /dev/null
+++ b/vala/valainterfaceregisterfunction.vala
@@ -0,0 +1,83 @@
+/* valainterfaceregisterfunction.vala
+ *
+ * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
+ *
+ * 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>
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+using GLib;
+
+/**
+ * C function to register an interface at runtime.
+ */
+public class Vala.InterfaceRegisterFunction : TypeRegisterFunction {
+ /**
+ * Specifies the interface to be registered.
+ */
+ public Interface! interface_reference { get; set construct; }
+
+ public InterfaceRegisterFunction (Interface! iface) {
+ interface_reference = iface;
+ }
+
+ public override DataType! get_type_declaration () {
+ return interface_reference;
+ }
+
+ public override ref string! get_type_struct_name () {
+ return interface_reference.get_type_cname ();
+ }
+
+ public override ref string! get_base_init_func_name () {
+ return "%s_base_init".printf (interface_reference.get_lower_case_cname (null));
+ }
+
+ public override ref string! get_class_init_func_name () {
+ return "NULL";
+ }
+
+ public override ref string! get_instance_struct_size () {
+ return "0";
+ }
+
+ public override ref string! get_instance_init_func_name () {
+ return "NULL";
+ }
+
+ public override ref string! get_parent_type_name () {
+ return "G_TYPE_INTERFACE";
+ }
+
+ public override ref CCodeFragment! get_type_interface_init_statements () {
+ var frag = new CCodeFragment ();
+
+ /* register all prerequisites */
+ foreach (TypeReference prereq_ref in interface_reference.get_prerequisites ()) {
+ var prereq = prereq_ref.data_type;
+
+ var func = new CCodeFunctionCall (new CCodeIdentifier ("g_type_interface_add_prerequisite"));
+ func.add_argument (new CCodeIdentifier ("%s_type_id".printf (interface_reference.get_lower_case_cname (null))));
+ func.add_argument (new CCodeIdentifier (prereq.get_type_id()));
+
+ frag.append (new CCodeExpressionStatement (func));
+ }
+
+ return frag;
+ }
+}
diff --git a/vala/valainterfacewriter.vala b/vala/valainterfacewriter.vala
new file mode 100644
index 000000000..e518ffcab
--- /dev/null
+++ b/vala/valainterfacewriter.vala
@@ -0,0 +1,619 @@
+/* valainterfacewriter.vala
+ *
+ * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
+ *
+ * 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>
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+using GLib;
+
+/**
+ * Code visitor generating Vala API file for the public interface.
+ */
+public class Vala.InterfaceWriter : CodeVisitor {
+ private CodeContext context;
+
+ File stream;
+
+ int indent;
+ /* at begin of line */
+ bool bol = true;
+
+ bool internal_scope = false;
+
+ string current_cheader_filename;
+
+ /**
+ * Writes the public interface of the specified code context into the
+ * specified file.
+ *
+ * @param context a code context
+ * @param filename a relative or absolute filename
+ */
+ public void write_file (CodeContext! context, string! filename) {
+ this.context = context;
+
+ stream = File.open (filename, "w");
+
+ /* we're only interested in non-pkg source files */
+ foreach (SourceFile file in context.get_source_files ()) {
+ if (!file.pkg) {
+ file.accept (this);
+ }
+ }
+
+ stream = null;
+ }
+
+ public override void visit_begin_namespace (Namespace! ns) {
+ if (ns.name == null) {
+ return;
+ }
+
+ current_cheader_filename = ns.get_cheader_filename ();
+
+ write_indent ();
+ write_string ("[CCode (cheader_filename = \"%s\")]".printf (current_cheader_filename));
+ write_newline ();
+
+ write_indent ();
+ write_string ("namespace ");
+ write_identifier (ns.name);
+ write_begin_block ();
+ }
+
+ public override void visit_end_namespace (Namespace! ns) {
+ if (ns.name == null) {
+ return;
+ }
+
+ write_end_block ();
+ write_newline ();
+ }
+
+ public override void visit_begin_class (Class! cl) {
+ if (cl.access == MemberAccessibility.PRIVATE) {
+ internal_scope = true;
+ return;
+ }
+
+ write_indent ();
+
+ var first = true;
+ string cheaders;
+ foreach (string cheader in cl.get_cheader_filenames ()) {
+ if (first) {
+ cheaders = cheader;
+ first = false;
+ } else {
+ cheaders = "%s, %s".printf (cheaders, cheader);
+ }
+ }
+ write_string ("[CCode (cheader_filename = \"%s\")]".printf (cheaders));
+ write_newline ();
+
+ write_indent ();
+ write_string ("public ");
+ if (cl.is_abstract) {
+ write_string ("abstract ");
+ }
+ write_string ("class ");
+ write_identifier (cl.name);
+
+ var base_types = cl.get_base_types ();
+ if (base_types != null) {
+ write_string (" : ");
+
+ bool first = true;
+ foreach (TypeReference base_type in base_types) {
+ if (!first) {
+ write_string (", ");
+ } else {
+ first = false;
+ }
+ write_string (base_type.data_type.symbol.get_full_name ());
+ }
+ }
+ write_begin_block ();
+ }
+
+ public override void visit_end_class (Class! cl) {
+ if (cl.access == MemberAccessibility.PRIVATE) {
+ internal_scope = false;
+ return;
+ }
+
+ write_end_block ();
+ write_newline ();
+ }
+
+ public override void visit_begin_struct (Struct! st) {
+ if (st.access == MemberAccessibility.PRIVATE) {
+ internal_scope = true;
+ return;
+ }
+
+ if (st.is_reference_type ()) {
+ write_indent ();
+ write_string ("[ReferenceType]");
+ }
+
+ write_indent ();
+ write_string ("public struct ");
+ write_identifier (st.name);
+ write_begin_block ();
+ }
+
+ public override void visit_end_struct (Struct! st) {
+ if (st.access == MemberAccessibility.PRIVATE) {
+ internal_scope = false;
+ return;
+ }
+
+ write_end_block ();
+ write_newline ();
+ }
+
+ public override void visit_begin_interface (Interface! iface) {
+ if (iface.access == MemberAccessibility.PRIVATE) {
+ internal_scope = true;
+ return;
+ }
+
+ write_indent ();
+ write_string ("public ");
+ write_string ("interface ");
+ write_identifier (iface.name);
+
+ write_begin_block ();
+ }
+
+ public override void visit_end_interface (Interface! iface) {
+ if (iface.access == MemberAccessibility.PRIVATE) {
+ internal_scope = false;
+ return;
+ }
+
+ write_end_block ();
+ write_newline ();
+ }
+
+ public override void visit_begin_enum (Enum! en) {
+ if (en.access == MemberAccessibility.PRIVATE) {
+ internal_scope = true;
+ return;
+ }
+
+ write_indent ();
+ write_string ("[CCode (cprefix = \"%s\")]".printf (en.get_cprefix ()));
+
+ write_indent ();
+ write_string ("public enum ");
+ write_identifier (en.name);
+ write_begin_block ();
+ }
+
+ public override void visit_end_enum (Enum! en) {
+ if (en.access == MemberAccessibility.PRIVATE) {
+ internal_scope = false;
+ return;
+ }
+
+ write_end_block ();
+ write_newline ();
+ }
+
+ public override void visit_enum_value (EnumValue! ev) {
+ if (internal_scope) {
+ return;
+ }
+
+ write_indent ();
+ write_identifier (ev.name);
+ write_string (",");
+ write_newline ();
+ }
+
+ public override void visit_begin_flags (Flags! fl) {
+ if (fl.access == MemberAccessibility.PRIVATE) {
+ internal_scope = true;
+ return;
+ }
+
+ write_indent ();
+ write_string ("[CCode (cprefix = \"%s\")]".printf (fl.get_cprefix ()));
+
+ write_indent ();
+ write_string ("public flags ");
+ write_identifier (fl.name);
+ write_begin_block ();
+ }
+
+ public override void visit_end_flags (Flags! fl) {
+ if (fl.access == MemberAccessibility.PRIVATE) {
+ internal_scope = false;
+ return;
+ }
+
+ write_end_block ();
+ write_newline ();
+ }
+
+ public override void visit_flags_value (FlagsValue! fv) {
+ if (internal_scope) {
+ return;
+ }
+
+ write_indent ();
+ write_identifier (fv.name);
+ write_string (",");
+ write_newline ();
+ }
+
+ public override void visit_constant (Constant! c) {
+ if (internal_scope) {
+ return;
+ }
+
+ write_indent ();
+ write_string ("public const ");
+ write_string (c.type_reference.data_type.symbol.get_full_name ());
+
+ write_string (" ");
+ write_identifier (c.name);
+ write_string (";");
+ write_newline ();
+ }
+
+ public override void visit_field (Field! f) {
+ if (internal_scope || f.access == MemberAccessibility.PRIVATE) {
+ return;
+ }
+
+ write_indent ();
+ write_string ("public ");
+ if (f.type_reference.data_type != null &&
+ f.type_reference.data_type.is_reference_type () &&
+ !f.type_reference.takes_ownership) {
+ write_string ("weak ");
+ }
+ write_string (f.type_reference.data_type.symbol.get_full_name ());
+
+ var type_args = f.type_reference.get_type_arguments ();
+ if (!(f.type_reference.data_type is Array) && type_args != null) {
+ write_string ("<");
+ foreach (TypeReference type_arg in type_args) {
+ if (!type_arg.takes_ownership) {
+ write_string ("weak ");
+ }
+ write_string (type_arg.data_type.symbol.get_full_name ());
+ }
+ write_string (">");
+ }
+
+ write_string (" ");
+ write_identifier (f.name);
+ write_string (";");
+ write_newline ();
+ }
+
+ private void write_params (List<FormalParameter> params) {
+ write_string ("(");
+
+ bool first = true;
+ foreach (FormalParameter param in params) {
+ if (!first) {
+ write_string (", ");
+ } else {
+ first = false;
+ }
+
+ if (param.ellipsis) {
+ write_string ("...");
+ continue;
+ }
+
+ if (param.type_reference.reference_to_value_type ||
+ param.type_reference.takes_ownership) {
+ write_string ("ref ");
+ } else if (param.type_reference.is_out) {
+ write_string ("out ");
+ }
+ write_string (param.type_reference.data_type.symbol.get_full_name ());
+
+ var type_args = param.type_reference.get_type_arguments ();
+ if (!(param.type_reference.data_type is Array) && type_args != null) {
+ write_string ("<");
+ foreach (TypeReference type_arg in type_args) {
+ if (type_arg.takes_ownership) {
+ write_string ("ref ");
+ }
+ write_string (type_arg.data_type.symbol.get_full_name ());
+ }
+ write_string (">");
+ }
+
+ if (param.type_reference.non_null) {
+ write_string ("!");
+ }
+
+ write_string (" ");
+ write_identifier (param.name);
+
+ if (param.default_expression != null) {
+ write_string (" = ");
+ write_string (param.default_expression.to_string ());
+ }
+ }
+
+ write_string (")");
+ }
+
+ public override void visit_begin_callback (Callback! cb) {
+ if (internal_scope || cb.access == MemberAccessibility.PRIVATE) {
+ return;
+ }
+
+ write_indent ();
+ write_string ("public callback ");
+
+ var type = cb.return_type.data_type;
+ if (type == null) {
+ write_string ("void");
+ } else {
+ if (cb.return_type.transfers_ownership) {
+ write_string ("ref ");
+ }
+ write_string (cb.return_type.data_type.symbol.get_full_name ());
+ }
+
+ write_string (" ");
+ write_identifier (cb.name);
+
+ write_string (" ");
+
+ write_params (cb.get_parameters ());
+
+ write_string (";");
+
+ write_newline ();
+ }
+
+ public override void visit_begin_method (Method! m) {
+ if (internal_scope || m.access == MemberAccessibility.PRIVATE || m.overrides) {
+ return;
+ }
+
+ if (m.no_array_length) {
+ bool array_found = (m.return_type != null && m.return_type.data_type is Array);
+ foreach (FormalParameter param in m.get_parameters ()) {
+ if (param.type_reference != null && param.type_reference.data_type is Array) {
+ array_found = true;
+ break;
+ }
+ }
+ if (array_found) {
+ write_indent ();
+ write_string ("[NoArrayLength]");
+ }
+ }
+ if (m.instance_last) {
+ write_indent ();
+ write_string ("[InstanceLast]");
+ }
+ if (m.instance_by_reference) {
+ write_indent ();
+ write_string ("[InstanceByReference]");
+ }
+ if (m.get_cname () != m.get_default_cname ()) {
+ write_indent ();
+ write_string ("[CCode (cname = \"%s\")]".printf (m.get_cname ()));
+ }
+
+ write_indent ();
+ write_string ("public");
+
+ if (m is CreationMethod) {
+ write_string (" ");
+ var datatype = (DataType) m.symbol.parent_symbol.node;
+ write_identifier (datatype.name);
+
+ if (m.name != null) {
+ write_string (".");
+ write_identifier (m.name);
+ }
+ } else if (!m.instance) {
+ write_string (" static");
+ } else if (m.is_abstract) {
+ write_string (" abstract");
+ } else if (m.is_virtual) {
+ write_string (" virtual");
+ }
+
+ if (!(m is CreationMethod)) {
+ write_string (" ");
+
+ var type = m.return_type.data_type;
+ if (type == null) {
+ write_string ("void");
+ } else {
+ if (m.return_type.transfers_ownership) {
+ } else if ((m.return_type.data_type != null && m.return_type.data_type.is_reference_type ()) || m.return_type.type_parameter != null) {
+ write_string ("weak ");
+ }
+ write_string (m.return_type.data_type.symbol.get_full_name ());
+ if (m.return_type.non_null) {
+ write_string ("!");
+ }
+ }
+
+ write_string (" ");
+ write_identifier (m.name);
+ }
+
+ write_string (" ");
+
+ write_params (m.get_parameters ());
+
+ write_string (";");
+
+ write_newline ();
+ }
+
+ public override void visit_begin_creation_method (CreationMethod! m) {
+ visit_begin_method (m);
+ }
+
+ public override void visit_begin_property (Property! prop) {
+ if (internal_scope) {
+ return;
+ }
+
+ if (prop.no_accessor_method) {
+ write_indent ();
+ write_string ("[NoAccessorMethod]");
+ }
+
+ write_indent ();
+ write_string ("public ");
+ if (!prop.type_reference.takes_ownership) {
+ write_string ("weak ");
+ }
+ write_string (prop.type_reference.data_type.symbol.get_full_name ());
+
+ var type_args = prop.type_reference.get_type_arguments ();
+ if (!(prop.type_reference.data_type is Array) && type_args != null) {
+ write_string ("<");
+ foreach (TypeReference type_arg in type_args) {
+ if (!type_arg.takes_ownership) {
+ write_string ("weak ");
+ }
+ write_string (type_arg.data_type.symbol.get_full_name ());
+ }
+ write_string (">");
+ }
+
+ write_string (" ");
+ write_identifier (prop.name);
+ write_string (" {");
+ if (prop.get_accessor != null) {
+ write_string (" get;");
+ }
+ if (prop.set_accessor != null) {
+ if (prop.set_accessor.writable) {
+ write_string (" set");
+ }
+ if (prop.set_accessor.construction) {
+ write_string (" construct");
+ }
+ write_string (";");
+ }
+ write_string (" }");
+ write_newline ();
+ }
+
+ public override void visit_begin_signal (Signal! sig) {
+ if (internal_scope || sig.access == MemberAccessibility.PRIVATE) {
+ return;
+ }
+
+ if (sig.has_emitter) {
+ write_indent ();
+ write_string ("[HasEmitter]");
+ }
+
+ write_indent ();
+ write_string ("public signal ");
+
+ var type = sig.return_type.data_type;
+ if (type == null) {
+ write_string ("void");
+ } else {
+ if (sig.return_type.transfers_ownership) {
+ write_string ("ref ");
+ }
+ write_string (sig.return_type.data_type.symbol.get_full_name ());
+ if (sig.return_type.non_null) {
+ write_string ("!");
+ }
+ }
+
+ write_string (" ");
+ write_identifier (sig.name);
+
+ write_string (" ");
+
+ write_params (sig.get_parameters ());
+
+ write_string (";");
+
+ write_newline ();
+ }
+
+ private void write_indent () {
+ int i;
+
+ if (!bol) {
+ stream.putc ('\n');
+ }
+
+ for (i = 0; i < indent; i++) {
+ stream.putc ('\t');
+ }
+
+ bol = false;
+ }
+
+ private void write_identifier (string! s) {
+ if (s == "base" || s == "callback" || s == "class" ||
+ s == "construct" || s == "flags" || s == "foreach" ||
+ s == "in" || s == "interface" || s == "lock" ||
+ s == "namespace" || s == "out" || s == "ref") {
+ stream.putc ('@');
+ }
+ write_string (s);
+ }
+
+ private void write_string (string! s) {
+ stream.printf ("%s", s);
+ bol = false;
+ }
+
+ private void write_newline () {
+ stream.putc ('\n');
+ bol = true;
+ }
+
+ private void write_begin_block () {
+ if (!bol) {
+ stream.putc (' ');
+ } else {
+ write_indent ();
+ }
+ stream.putc ('{');
+ write_newline ();
+ indent++;
+ }
+
+ private void write_end_block () {
+ indent--;
+ write_indent ();
+ stream.printf ("}");
+ }
+}
diff --git a/vala/valainvocationexpression.vala b/vala/valainvocationexpression.vala
new file mode 100644
index 000000000..8255d76e3
--- /dev/null
+++ b/vala/valainvocationexpression.vala
@@ -0,0 +1,106 @@
+/* valainvocationexpression.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;
+
+/**
+ * Represents an invocation expression in the source code.
+ */
+public class Vala.InvocationExpression : Expression {
+ /**
+ * The method to call.
+ */
+ public Expression! call {
+ get {
+ return _call;
+ }
+ set construct {
+ _call = value;
+ _call.parent_node = this;
+ }
+ }
+
+ public Expression! _call;
+
+ private List<Expression> argument_list;
+
+ /**
+ * Creates a new invocation expression.
+ *
+ * @param call method to call
+ * @param source reference to source code
+ * @return newly created invocation expression
+ */
+ public InvocationExpression (Expression! _call, SourceReference source = null) {
+ call = _call;
+ source_reference = source;
+ }
+
+ /**
+ * Appends the specified expression to the list of arguments.
+ *
+ * @param arg an argument
+ */
+ public void add_argument (Expression! arg) {
+ argument_list.append (arg);
+ arg.parent_node = this;
+ }
+
+ /**
+ * Returns a copy of the argument list.
+ *
+ * @return argument list
+ */
+ public ref List<weak Expression> get_argument_list () {
+ return argument_list.copy ();
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ call.accept (visitor);
+
+ visitor.visit_begin_invocation_expression (this);
+
+ // iterate over list copy as list may change in loop body
+ foreach (Expression expr in argument_list.copy ()) {
+ expr.accept (visitor);
+ }
+
+ visitor.visit_end_invocation_expression (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (call == old_node) {
+ call = (Expression) new_node;
+ }
+
+ weak List<Expression> l = argument_list.find (old_node);
+ if (l != null) {
+ if (new_node.parent_node != null) {
+ return;
+ }
+
+ argument_list.insert_before (l, new_node);
+ argument_list.remove_link (l);
+ new_node.parent_node = this;
+ }
+ }
+}
diff --git a/vala/valainvokable.vala b/vala/valainvokable.vala
new file mode 100644
index 000000000..f5dc56dc0
--- /dev/null
+++ b/vala/valainvokable.vala
@@ -0,0 +1,49 @@
+/* valainvokable.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * Represents a possibly invokable code object.
+ */
+public interface Vala.Invokable /* : CodeNode */ {
+ /**
+ * Returns whether this code object is invokable.
+ *
+ * @return true if invokable, false otherwise
+ */
+ public abstract bool is_invokable ();
+
+ /**
+ * Returns the return type of this invokable.
+ *
+ * @return return type
+ */
+ public abstract TypeReference get_return_type ();
+
+ /**
+ * Returns copy of the list of invocation parameters.
+ *
+ * @return parameter list
+ */
+ public abstract ref List<weak FormalParameter> get_parameters ();
+}
diff --git a/vala/valalambdaexpression.vala b/vala/valalambdaexpression.vala
new file mode 100644
index 000000000..03dbae637
--- /dev/null
+++ b/vala/valalambdaexpression.vala
@@ -0,0 +1,109 @@
+/* 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;
+
+/**
+ * Represents a lambda expression in the source code. Lambda expressions are
+ * anonymous methods with implicitly typed parameters.
+ */
+public class Vala.LambdaExpression : Expression {
+ /**
+ * The expression body of this lambda expression. Only one of
+ * expression_body or statement_body may be set.
+ */
+ public Expression expression_body { get; set; }
+
+ /**
+ * The statement body of this lambda expression. Only one of
+ * expression_body or statement_body may be set.
+ */
+ public Block statement_body { get; set; }
+
+ /**
+ * The generated method.
+ */
+ public Method method { get; set; }
+
+ private List<string> parameters;
+
+ /**
+ * Creates a new lambda expression.
+ *
+ * @param body expression body
+ * @param source reference to source code
+ * @return newly created lambda expression
+ */
+ public LambdaExpression (Expression! body, SourceReference source) {
+ expression_body = body;
+ source_reference = source;
+ }
+
+ /**
+ * Creates a new lambda expression with statement body.
+ *
+ * @param body statement body
+ * @param source reference to source code
+ * @return newly created lambda expression
+ */
+ public LambdaExpression.with_statement_body (Block! body, SourceReference source) {
+ statement_body = body;
+ source_reference = source;
+ }
+
+ /**
+ * Appends implicitly typed parameter.
+ *
+ * @param param parameter name
+ */
+ public void add_parameter (string! param) {
+ parameters.append (param);
+ }
+
+ /**
+ * Returns copy of parameter list.
+ *
+ * @return parameter list
+ */
+ public ref List<weak string> get_parameters () {
+ return parameters.copy ();
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_lambda_expression (this);
+
+ if (method == null) {
+ if (expression_body != null) {
+ expression_body.accept (visitor);
+ visitor.visit_end_full_expression (expression_body);
+ } else if (statement_body != null) {
+ statement_body.accept (visitor);
+ }
+ }
+
+ visitor.visit_end_lambda_expression (this);
+
+ if (method != null) {
+ method.accept (visitor);
+ }
+ }
+}
diff --git a/vala/valaliteral.vala b/vala/valaliteral.vala
new file mode 100644
index 000000000..01886bf9f
--- /dev/null
+++ b/vala/valaliteral.vala
@@ -0,0 +1,33 @@
+/* valaliteral.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * Base class for all literals in the source code.
+ */
+public abstract class Vala.Literal : CodeNode {
+ /**
+ * Specifies the type of this literal.
+ */
+ public TypeReference static_type { get; set; }
+}
diff --git a/vala/valaliteralexpression.vala b/vala/valaliteralexpression.vala
new file mode 100644
index 000000000..af96424f6
--- /dev/null
+++ b/vala/valaliteralexpression.vala
@@ -0,0 +1,55 @@
+/* valaliteralexpression.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;
+
+/**
+ * Represents a literal expression in the source code.
+ */
+public class Vala.LiteralExpression : Expression {
+ /**
+ * The literal.
+ */
+ public Literal literal { get; construct; }
+
+ /**
+ * Creates a new literal expression.
+ *
+ * @param literal a literal
+ * @param source reference to source code
+ * @return newly created literal expression
+ */
+ public LiteralExpression (Literal! _literal, SourceReference source = null) {
+ literal = _literal;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ literal.accept (visitor);
+
+ visitor.visit_literal_expression (this);
+ }
+
+ public override ref string! to_string () {
+ return literal.to_string ();
+ }
+}
diff --git a/vala/valalocalvariabledeclaration.vala b/vala/valalocalvariabledeclaration.vala
new file mode 100644
index 000000000..acf9427df
--- /dev/null
+++ b/vala/valalocalvariabledeclaration.vala
@@ -0,0 +1,90 @@
+/* valalocalvariabledeclaration.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;
+
+/**
+ * Represents a local variable declaration in the source code.
+ */
+public class Vala.LocalVariableDeclaration : CodeNode {
+ /**
+ * The type of the local variable.
+ */
+ public TypeReference type_reference { get; set; }
+
+ private List<VariableDeclarator> variable_declarators;
+
+ /**
+ * Creates a new local variable declaration.
+ *
+ * @param type type of the variable
+ * @param source reference to source code
+ * @return newly created local variable declaration
+ */
+ public LocalVariableDeclaration (TypeReference type, SourceReference source) {
+ type_reference = type;
+ source_reference = source;
+ }
+
+ /**
+ * Creates a new implicitly typed local variable declaration. The type
+ * of the variable is inferred from the expression used to initialize
+ * the variable.
+ *
+ * @param source reference to source code
+ * @return newly created local variable declaration
+ */
+ public LocalVariableDeclaration.var_type (SourceReference source) {
+ source_reference = source;
+ }
+
+ /**
+ * Add the specified variable declarator to this local variable
+ * declaration.
+ *
+ * @param declarator a variable declarator
+ */
+ public void add_declarator (VariableDeclarator! declarator) {
+ variable_declarators.append (declarator);
+ }
+
+ /**
+ * Returns a copy of the list of variable declarators.
+ *
+ * @return variable declarator list
+ */
+ public ref List<weak VariableDeclarator> get_variable_declarators () {
+ return variable_declarators.copy ();
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ if (type_reference != null) {
+ type_reference.accept (visitor);
+ }
+
+ foreach (VariableDeclarator decl in variable_declarators) {
+ decl.accept (visitor);
+ }
+
+ visitor.visit_local_variable_declaration (this);
+ }
+}
diff --git a/vala/valalockable.vala b/vala/valalockable.vala
new file mode 100644
index 000000000..69bcae50f
--- /dev/null
+++ b/vala/valalockable.vala
@@ -0,0 +1,36 @@
+/* valalockable.vala
+ *
+ * Copyright (C) 2006 Raffaele Sandrini
+ *
+ * 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:
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+/**
+ * Represents a lockable object.
+ */
+public interface Vala.Lockable {
+ /**
+ * Indicates a specific lockable object beeing actually locked somewhere.
+ */
+ public abstract bool get_lock_used ();
+
+ /**
+ * Set this lockable object as beeing locked somewhere.
+ */
+ public abstract void set_lock_used (bool used);
+}
diff --git a/vala/valalockstatement.vala b/vala/valalockstatement.vala
new file mode 100644
index 000000000..775725e08
--- /dev/null
+++ b/vala/valalockstatement.vala
@@ -0,0 +1,50 @@
+/* valalockstatement.vala
+ *
+ * Copyright (C) 2006 Raffaele Sandrini
+ *
+ * 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:
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+using GLib;
+
+/**
+ * Represents a lock statement e.g. "lock (a) { f(a) }".
+ */
+public class Vala.LockStatement : Statement {
+ /**
+ * Expression representing the resource to be locked.
+ */
+ public Expression! resource { get; set construct; }
+
+ /**
+ * The statement during its execution the resource is locked.
+ */
+ public Statement! body { get; set construct; }
+
+ public LockStatement (Expression _resource, Statement _body, SourceReference source) {
+ resource = _resource;
+ body = _body;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ resource.accept (visitor);
+ body.accept (visitor);
+ visitor.visit_lock_statement (this);
+ }
+}
diff --git a/vala/valamember.vala b/vala/valamember.vala
new file mode 100644
index 000000000..651a98b1e
--- /dev/null
+++ b/vala/valamember.vala
@@ -0,0 +1,30 @@
+/* valamember.vala
+ *
+ * Copyright (C) 2006 Raffaele Sandrini
+ *
+ * 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:
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+/**
+ * Represents a general class member.
+ */
+public class Vala.Member : CodeNode {
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_member (this);
+ }
+}
diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala
new file mode 100644
index 000000000..d8052ee2d
--- /dev/null
+++ b/vala/valamemberaccess.vala
@@ -0,0 +1,114 @@
+/* valamemberaccess.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * Represents an access to a type member in the source code.
+ */
+public class Vala.MemberAccess : Expression {
+ /**
+ * The parent of the member.
+ */
+ public Expression inner {
+ get {
+ return _inner;
+ }
+ set {
+ _inner = value;
+ if (_inner != null) {
+ _inner.parent_node = this;
+ }
+ }
+ }
+
+ /**
+ * The name of the member.
+ */
+ public string! member_name { get; set construct; }
+
+ private Expression _inner;
+ private List<TypeReference> type_argument_list;
+
+ /**
+ * Creates a new member access expression.
+ *
+ * @param inner parent of the member
+ * @param member member name
+ * @param source reference to source code
+ * @return newly created member access expression
+ */
+ public MemberAccess (Expression _inner, string! member, SourceReference source = null) {
+ inner = _inner;
+ member_name = member;
+ source_reference = source;
+ }
+
+ public MemberAccess.simple (string! member, SourceReference source = null) {
+ member_name = member;
+ source_reference = source;
+ }
+
+ /**
+ * Appends the specified type as generic type argument.
+ *
+ * @param arg a type reference
+ */
+ public void add_type_argument (TypeReference! arg) {
+ type_argument_list.append (arg);
+ }
+
+ /**
+ * Returns a copy of the list of generic type arguments.
+ *
+ * @return type argument list
+ */
+ public ref List<weak TypeReference> get_type_arguments () {
+ return type_argument_list.copy ();
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ if (inner != null) {
+ inner.accept (visitor);
+ }
+
+ foreach (TypeReference type_arg in type_argument_list) {
+ type_arg.accept (visitor);
+ }
+
+ visitor.visit_member_access (this);
+ }
+
+ public override ref string! to_string () {
+ if (inner == null) {
+ return member_name;
+ } else {
+ return "%s.%s".printf (inner.to_string (), member_name);
+ }
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (inner == old_node) {
+ inner = (Expression) new_node;
+ }
+ }
+}
diff --git a/vala/valamemberaccessibility.vala b/vala/valamemberaccessibility.vala
new file mode 100644
index 000000000..b8912194c
--- /dev/null
+++ b/vala/valamemberaccessibility.vala
@@ -0,0 +1,30 @@
+/* valamemberaccessibility.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;
+
+public enum Vala.MemberAccessibility {
+ PRIVATE,
+ INTERNAL,
+ PROTECTED,
+ PUBLIC
+}
diff --git a/vala/valamemorymanager.vala b/vala/valamemorymanager.vala
new file mode 100644
index 000000000..4d1cca382
--- /dev/null
+++ b/vala/valamemorymanager.vala
@@ -0,0 +1,252 @@
+/* valamemorymanager.vala
+ *
+ * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
+ *
+ * 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>
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+using GLib;
+
+/**
+ * Code visitor analyzing memory usage. The memory manager finds leaked and
+ * copied references.
+ */
+public class Vala.MemoryManager : CodeVisitor {
+ Symbol current_symbol;
+
+ /**
+ * Analyze memory usage in the specified code context.
+ *
+ * @param context a code context
+ */
+ public void analyze (CodeContext! context) {
+ context.accept (this);
+ }
+
+ private void visit_possibly_leaked_expression (Expression! expr) {
+ if (expr.static_type != null &&
+ ((expr.static_type.data_type != null &&
+ expr.static_type.data_type.is_reference_type ()) ||
+ expr.static_type.type_parameter != null) &&
+ expr.static_type.transfers_ownership) {
+ /* mark reference as leaked */
+ expr.ref_leaked = true;
+ }
+ }
+
+ private void visit_possibly_missing_copy_expression (Expression! expr) {
+ if (expr.static_type != null &&
+ ((expr.static_type.data_type != null &&
+ expr.static_type.data_type.is_reference_type ()) ||
+ expr.static_type.type_parameter != null) &&
+ !expr.static_type.transfers_ownership) {
+ /* mark reference as missing */
+ expr.ref_missing = true;
+ }
+ }
+
+ public override void visit_field (Field! f) {
+ if (f.initializer != null) {
+ if (f.type_reference.takes_ownership) {
+ visit_possibly_missing_copy_expression (f.initializer);
+ } else {
+ visit_possibly_leaked_expression (f.initializer);
+ }
+ }
+ }
+
+ public override void visit_begin_method (Method! m) {
+ current_symbol = m.symbol;
+ }
+
+ public override void visit_begin_creation_method (CreationMethod! m) {
+ current_symbol = m.symbol;
+ }
+
+ public override void visit_begin_property (Property! prop) {
+ current_symbol = prop.symbol;
+ }
+
+ public override void visit_named_argument (NamedArgument! n) {
+ visit_possibly_leaked_expression (n.argument);
+ }
+
+ public override void visit_variable_declarator (VariableDeclarator! decl) {
+ if (decl.initializer != null) {
+ if (decl.type_reference.takes_ownership) {
+ visit_possibly_missing_copy_expression (decl.initializer);
+ } else {
+ visit_possibly_leaked_expression (decl.initializer);
+ }
+ }
+ }
+
+ public override void visit_expression_statement (ExpressionStatement! stmt) {
+ visit_possibly_leaked_expression (stmt.expression);
+ }
+
+ public override void visit_end_return_statement (ReturnStatement! stmt) {
+ if (stmt.return_expression != null) {
+ if (current_symbol.node is Method) {
+ var m = (Method) current_symbol.node;
+
+ if (m.return_type.transfers_ownership) {
+ visit_possibly_missing_copy_expression (stmt.return_expression);
+ } else {
+ visit_possibly_leaked_expression (stmt.return_expression);
+ }
+ } else {
+ /* property get accessor */
+ visit_possibly_leaked_expression (stmt.return_expression);
+ }
+ }
+ }
+
+ public override void visit_member_access (MemberAccess! expr) {
+ if (expr.inner != null) {
+ visit_possibly_leaked_expression (expr.inner);
+ }
+ }
+
+ public override void visit_end_invocation_expression (InvocationExpression! expr) {
+ List<weak FormalParameter> params;
+
+ var msym = expr.call.symbol_reference;
+ if (msym.node is VariableDeclarator) {
+ var decl = (VariableDeclarator) msym.node;
+ var cb = (Callback) decl.type_reference.data_type;
+ params = cb.get_parameters ();
+ } else if (msym.node is FormalParameter) {
+ var param = (FormalParameter) msym.node;
+ var cb = (Callback) param.type_reference.data_type;
+ params = cb.get_parameters ();
+ } else if (msym.node is Field) {
+ var f = (Field) msym.node;
+ var cb = (Callback) f.type_reference.data_type;
+ params = cb.get_parameters ();
+ } else if (msym.node is Method) {
+ var m = (Method) msym.node;
+ params = m.get_parameters ();
+ } else if (msym.node is Signal) {
+ var sig = (Signal) msym.node;
+ params = sig.get_parameters ();
+ }
+ weak List<weak FormalParameter> params_it = params;
+ foreach (Expression arg in expr.get_argument_list ()) {
+ if (params_it != null) {
+ var param = (FormalParameter) params_it.data;
+ if (!param.ellipsis
+ && ((param.type_reference.data_type != null
+ && param.type_reference.data_type.is_reference_type ())
+ || param.type_reference.type_parameter != null)) {
+ bool is_ref = param.type_reference.takes_ownership;
+ if (is_ref && param.type_reference.type_parameter != null) {
+ // TODO move this to semantic analyzer
+ if (expr.call is MemberAccess) {
+ var ma = (MemberAccess) expr.call;
+ ref TypeReference instance_type = ma.inner.static_type;
+ // trace type arguments back to the datatype where the method has been declared
+ while (instance_type.data_type != msym.parent_symbol.node) {
+ List<weak TypeReference> base_types = null;
+ if (instance_type.data_type is Class) {
+ var cl = (Class) instance_type.data_type;
+ base_types = cl.get_base_types ();
+ } else if (instance_type.data_type is Interface) {
+ var iface = (Interface) instance_type.data_type;
+ base_types = iface.get_prerequisites ();
+ } else {
+ Report.error (expr.source_reference, "internal error: unsupported generic type");
+ expr.error = true;
+ return;
+ }
+ foreach (TypeReference base_type in base_types) {
+ if (SemanticAnalyzer.symbol_lookup_inherited (base_type.data_type.symbol, msym.name) != null) {
+ // construct a new type reference for the base type with correctly linked type arguments
+ var instance_base_type = new TypeReference ();
+ instance_base_type.data_type = base_type.data_type;
+ foreach (TypeReference type_arg in base_type.get_type_arguments ()) {
+ if (type_arg.type_parameter != null) {
+ // link to type argument of derived type
+ int param_index = instance_type.data_type.get_type_parameter_index (type_arg.type_parameter.name);
+ if (param_index == -1) {
+ Report.error (expr.source_reference, "internal error: unknown type parameter %s".printf (type_arg.type_parameter.name));
+ expr.error = true;
+ return;
+ }
+ type_arg = instance_type.get_type_arguments ().nth_data (param_index);
+ }
+ instance_base_type.add_type_argument (type_arg);
+ }
+ instance_type = instance_base_type;
+ }
+ }
+ }
+ if (instance_type.data_type != msym.parent_symbol.node) {
+ Report.error (expr.source_reference, "internal error: generic type parameter tracing not supported yet");
+ expr.error = true;
+ return;
+ }
+ int param_index = instance_type.data_type.get_type_parameter_index (param.type_reference.type_parameter.name);
+ if (param_index == -1) {
+ Report.error (expr.source_reference, "internal error: unknown type parameter %s".printf (param.type_reference.type_parameter.name));
+ expr.error = true;
+ return;
+ }
+ var param_type = (TypeReference) instance_type.get_type_arguments ().nth_data (param_index);
+ if (param_type == null) {
+ Report.error (expr.source_reference, "internal error: no actual argument found for type parameter %s".printf (param.type_reference.type_parameter.name));
+ expr.error = true;
+ return;
+ }
+ is_ref = param_type.takes_ownership;
+ }
+ }
+
+ if (is_ref) {
+ visit_possibly_missing_copy_expression (arg);
+ } else {
+ visit_possibly_leaked_expression (arg);
+ }
+ } else {
+ visit_possibly_leaked_expression (arg);
+ }
+
+ params_it = params_it.next;
+ } else {
+ visit_possibly_leaked_expression (arg);
+ }
+ }
+ }
+
+ public override void visit_binary_expression (BinaryExpression! expr) {
+ visit_possibly_leaked_expression (expr.left);
+ visit_possibly_leaked_expression (expr.right);
+ }
+
+ public override void visit_end_assignment (Assignment! a) {
+ if (a.left is PointerIndirection || (a.left.symbol_reference != null && a.left.symbol_reference.node is Signal)) {
+ } else {
+ if (a.left.static_type.takes_ownership) {
+ visit_possibly_missing_copy_expression (a.right);
+ } else {
+ visit_possibly_leaked_expression (a.right);
+ }
+ }
+ }
+}
diff --git a/vala/valamethod.vala b/vala/valamethod.vala
new file mode 100644
index 000000000..0e9dd4e2e
--- /dev/null
+++ b/vala/valamethod.vala
@@ -0,0 +1,322 @@
+/* valamethod.vala
+ *
+ * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
+ *
+ * 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>
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+using GLib;
+
+/**
+ * Represents a type or namespace method.
+ */
+public class Vala.Method : Member, Invokable {
+ /**
+ * The symbol name of this method.
+ */
+ public string name { get; set; }
+
+ /**
+ * The return type of this method.
+ */
+ public TypeReference return_type { get; set; }
+
+ public Block body { get; set; }
+
+ /**
+ * Specifies the accessibility of this method. Public accessibility
+ * doesn't limit access. Default accessibility limits access to this
+ * program or library. Private accessibility limits access to instances
+ * of the contained type.
+ */
+ public MemberAccessibility access;
+
+ /**
+ * Specifies whether this method may only be called with an instance of
+ * the contained type.
+ */
+ public bool instance {
+ get {
+ return _instance;
+ }
+ set {
+ _instance = value;
+ }
+ }
+
+ /**
+ * Specifies whether this method is abstract. Abstract methods have no
+ * body, may only be specified within abstract classes, and must be
+ * overriden by derived non-abstract classes.
+ */
+ public bool is_abstract { get; set; }
+
+ /**
+ * Specifies whether this method is virtual. Virtual methods may be
+ * overridden by derived classes.
+ */
+ public bool is_virtual { get; set; }
+
+ /**
+ * Specifies whether this method overrides a virtual or abstract method
+ * of a base type.
+ */
+ public bool overrides { get; set; }
+
+ /**
+ * Specifies whether the C method returns a new instance pointer which
+ * may be different from the previous instance pointer. Only valid for
+ * imported methods.
+ */
+ public bool returns_modified_pointer { get; set; }
+
+ /**
+ * Specifies whether the instance pointer should be passed as the first
+ * or as the last argument in C code. Defaults to first.
+ */
+ public bool instance_last { get; set; }
+
+ /**
+ * Specifies whether the instance of a value type should be passed by
+ * reference. Only valid for instance methods of value types.
+ */
+ public bool instance_by_reference { get; set; }
+
+ /**
+ * Specifies the virtual or abstract method this method overrides.
+ * Reference must be weak as virtual methods set base_method to
+ * themselves.
+ */
+ public weak Method base_method { get; set; }
+
+ /**
+ * Specifies the abstract interface method this method implements.
+ */
+ public Method base_interface_method { get; set; }
+
+ /**
+ * Specifies the generated `this' parameter for instance methods.
+ */
+ public FormalParameter this_parameter { get; set; }
+
+ /**
+ * Specifies whether the array length should implicitly be passed
+ * if the parameter type is an array.
+ */
+ public bool no_array_length {
+ get {
+ return _no_array_length;
+ }
+ set {
+ _no_array_length = value;
+ foreach (FormalParameter param in parameters) {
+ param.no_array_length = value;
+ }
+ }
+ }
+
+ /**
+ * Specifies whether this method expects printf-style format arguments.
+ */
+ public bool printf_format { get; set; }
+
+ private bool _instance = true;
+ private List<FormalParameter> parameters;
+ private string cname;
+ private bool _no_array_length;
+
+ /**
+ * Creates a new method.
+ *
+ * @param name method name
+ * @param return_type method return type
+ * @param source reference to source code
+ * @return newly created method
+ */
+ public Method (string _name, TypeReference _return_type, SourceReference source = null) {
+ name = _name;
+ return_type = _return_type;
+ source_reference = source;
+ }
+
+ /**
+ * Appends parameter to this method.
+ *
+ * @param param a formal parameter
+ */
+ public void add_parameter (FormalParameter! param) {
+ if (no_array_length) {
+ param.no_array_length = true;
+ }
+
+ parameters.append (param);
+ }
+
+ public ref List<weak FormalParameter> get_parameters () {
+ return parameters.copy ();
+ }
+
+ public TypeReference get_return_type () {
+ return return_type;
+ }
+
+ public bool is_invokable () {
+ return true;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_method (this);
+
+ if (return_type != null) {
+ return_type.accept (visitor);
+ }
+
+ foreach (FormalParameter param in parameters) {
+ param.accept (visitor);
+ }
+
+ if (body != null) {
+ body.accept (visitor);
+ }
+
+ visitor.visit_end_method (this);
+ }
+
+ /**
+ * Returns the interface name of this method as it is used in C code.
+ *
+ * @return the name to be used in C code
+ */
+ public string! get_cname () {
+ if (cname == null) {
+ cname = get_default_cname ();
+ }
+ return cname;
+ }
+
+ /**
+ * Returns the default interface name of this method as it is used in C
+ * code.
+ *
+ * @return the name to be used in C code by default
+ */
+ public virtual ref string! get_default_cname () {
+ var parent = symbol.parent_symbol.node;
+ if (parent is DataType) {
+ if (name.has_prefix ("_")) {
+ return "_%s%s".printf (((DataType) parent).get_lower_case_cprefix (), name.offset (1));
+ } else {
+ return "%s%s".printf (((DataType) parent).get_lower_case_cprefix (), name);
+ }
+ } else if (parent is Namespace) {
+ return "%s%s".printf (((Namespace) parent).get_lower_case_cprefix (), name);
+ } else {
+ return name;
+ }
+ }
+
+ /**
+ * Returns the implementation name of this data type as it is used in C
+ * code.
+ *
+ * @return the name to be used in C code
+ */
+ public ref string! get_real_cname () {
+ if (base_method != null || base_interface_method != null) {
+ var parent = (Class) symbol.parent_symbol.node;
+ return "%s_real_%s".printf (parent.get_lower_case_cname (null), name);
+ } else {
+ return get_cname ();
+ }
+ }
+
+ /**
+ * Sets the name of this method as it is used in C code.
+ *
+ * @param cname the name to be used in C code
+ */
+ public void set_cname (string cname) {
+ this.cname = cname;
+ }
+
+ private void process_ccode_attribute (Attribute a) {
+ if (a.has_argument ("cname")) {
+ set_cname (a.get_string ("cname"));
+ }
+ }
+
+ /**
+ * Process all associated attributes.
+ */
+ public void process_attributes () {
+ foreach (Attribute a in attributes) {
+ if (a.name == "CCode") {
+ process_ccode_attribute (a);
+ } else if (a.name == "ReturnsModifiedPointer") {
+ returns_modified_pointer = true;
+ } else if (a.name == "InstanceLast") {
+ instance_last = true;
+ } else if (a.name == "InstanceByReference") {
+ instance_by_reference = true;
+ } else if (a.name == "FloatingReference") {
+ return_type.floating_reference = true;
+ } else if (a.name == "NoArrayLength") {
+ no_array_length = true;
+ } else if (a.name == "PrintfFormat") {
+ printf_format = true;
+ }
+ }
+ }
+
+ /**
+ * Checks whether the arguments and return type of the specified method
+ * matches this method.
+ *
+ * @param m a method
+ * @return true if the specified method is compatible to this method
+ */
+ public bool equals (Method! m2) {
+ if (!m2.return_type.equals (return_type)) {
+ return false;
+ }
+
+ var method_params = m2.get_parameters ();
+ weak List<weak FormalParameter> method_params_it = method_params;
+ foreach (FormalParameter param in parameters) {
+ /* method may not expect less arguments */
+ if (method_params_it == null) {
+ return false;
+ }
+
+ var method_param = (FormalParameter) method_params_it.data;
+ if (!method_param.type_reference.equals (param.type_reference)) {
+ return false;
+ }
+
+ method_params_it = method_params_it.next;
+ }
+
+ /* method may not expect more arguments */
+ if (method_params_it != null) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/vala/valanamedargument.vala b/vala/valanamedargument.vala
new file mode 100644
index 000000000..cb7012d7c
--- /dev/null
+++ b/vala/valanamedargument.vala
@@ -0,0 +1,59 @@
+/* valanamedargument.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;
+
+/**
+ * Represents a named argument in the source code. A named argument may be used
+ * when creating objects and attributes where no parameter list exists.
+ */
+public class Vala.NamedArgument : CodeNode {
+ /**
+ * The name of a property.
+ */
+ public string! name { get; set construct; }
+
+ /**
+ * The expression the property should assign.
+ */
+ public Expression! argument { get; set construct; }
+
+ /**
+ * Creates a new named argument.
+ *
+ * @param name property name
+ * @param arg property value expression
+ * @param source reference to source code
+ * @return newly created named argument
+ */
+ public NamedArgument (string! _name, Expression! arg, SourceReference source) {
+ name = _name;
+ argument = arg;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ argument.accept (visitor);
+
+ visitor.visit_named_argument (this);
+ }
+}
diff --git a/vala/valanamespace.vala b/vala/valanamespace.vala
new file mode 100644
index 000000000..3b63cba42
--- /dev/null
+++ b/vala/valanamespace.vala
@@ -0,0 +1,379 @@
+/* valanamespace.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * Represents a namespace declaration in the source code.
+ */
+public class Vala.Namespace : CodeNode {
+ /**
+ * The name of this namespace.
+ */
+ public string name { get; set; }
+
+ private List<Class> classes;
+ private List<Interface> interfaces;
+ private List<Struct> structs;
+ private List<Enum> enums;
+ private List<Flags> flags_;
+ private List<Callback> callbacks;
+ private List<Constant> constants;
+ private List<Field> fields;
+ private List<Method> methods;
+
+ private string cprefix;
+ private string lower_case_cprefix;
+
+ private List<string> cheader_filenames;
+
+ /**
+ * Creates a new namespace.
+ *
+ * @param name namespace name
+ * @param source reference to source code
+ * @return newly created namespace
+ */
+ public Namespace (string _name, SourceReference source = null) {
+ name = _name;
+ source_reference = source;
+ }
+
+ /**
+ * Adds the specified class to this namespace.
+ *
+ * @param cl a class
+ */
+ public void add_class (Class! cl) {
+ classes.append (cl);
+ cl.@namespace = this;
+ }
+
+ /**
+ * Removes the specified class from this namespace.
+ *
+ * @param cl a class
+ */
+ public void remove_class (Class! cl) {
+ cl.@namespace = null;
+ classes.remove (cl);
+ }
+
+ /**
+ * Adds the specified interface to this namespace.
+ *
+ * @param iface an interface
+ */
+ public void add_interface (Interface! iface) {
+ interfaces.append (iface);
+ iface.@namespace = this;
+ }
+
+ /**
+ * Adds the specified struct to this namespace.
+ *
+ * @param st a struct
+ */
+ public void add_struct (Struct! st) {
+ structs.append (st);
+ st.@namespace = this;
+ }
+
+ /**
+ * Adds the specified enum to this namespace.
+ *
+ * @param en an enum
+ */
+ public void add_enum (Enum! en) {
+ enums.append (en);
+ en.@namespace = this;
+ }
+
+ /**
+ * Adds the specified flags to this namespace.
+ *
+ * @param fl a flags
+ */
+ public void add_flags (Flags! fl) {
+ flags_.append (fl);
+ fl.@namespace = this;
+ }
+
+ /**
+ * Adds the specified callback to this namespace.
+ *
+ * @param cb a callback
+ */
+ public void add_callback (Callback! cb) {
+ callbacks.append (cb);
+ cb.@namespace = this;
+ }
+
+ /**
+ * Returns a copy of the list of structs.
+ *
+ * @return struct list
+ */
+ public ref List<weak Struct> get_structs () {
+ return structs.copy ();
+ }
+
+ /**
+ * Returns a copy of the list of classes.
+ *
+ * @return class list
+ */
+ public ref List<weak Class> get_classes () {
+ return classes.copy ();
+ }
+
+ /**
+ * Returns a copy of the list of interfaces.
+ *
+ * @return interface list
+ */
+ public ref List<weak Interface> get_interfaces () {
+ return interfaces.copy ();
+ }
+
+ /**
+ * Adds the specified constant to this namespace.
+ *
+ * @param constant a constant
+ */
+ public void add_constant (Constant! constant) {
+ constants.append (constant);
+ }
+
+ /**
+ * Adds the specified field to this namespace.
+ *
+ * @param f a field
+ */
+ public void add_field (Field! f) {
+ fields.append (f);
+ }
+
+ /**
+ * Adds the specified method to this namespace.
+ *
+ * @param m a method
+ */
+ public void add_method (Method! m) {
+ methods.append (m);
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_namespace (this);
+
+ /* process enums and flags first to avoid order problems in C code */
+ foreach (Enum en in enums) {
+ en.accept (visitor);
+ }
+
+ foreach (Flags fl in flags_) {
+ fl.accept (visitor);
+ }
+
+ foreach (Class cl in classes) {
+ cl.accept (visitor);
+ }
+
+ foreach (Interface iface in interfaces) {
+ iface.accept (visitor);
+ }
+
+ foreach (Struct st in structs) {
+ st.accept (visitor);
+ }
+
+ foreach (Callback cb in callbacks) {
+ cb.accept (visitor);
+ }
+
+ foreach (Constant c in constants) {
+ c.accept (visitor);
+ }
+
+ foreach (Field f in fields) {
+ f.accept (visitor);
+ }
+
+ foreach (Method m in methods) {
+ m.accept (visitor);
+ }
+
+ visitor.visit_end_namespace (this);
+ }
+
+ /**
+ * Converts a string from CamelCase to lower_case.
+ *
+ * @param camel_case a string in camel case
+ * @return the specified string converted to lower case
+ */
+ public static ref string! camel_case_to_lower_case (string! camel_case) {
+ String result = new String ("");
+
+ string i = camel_case;
+
+ bool first = true;
+ while (i.len () > 0) {
+ unichar c = i.get_char ();
+ if (c.isupper () && !first) {
+ /* current character is upper case and
+ * we're not at the beginning */
+ string t = i.prev_char ();
+ bool prev_upper = t.get_char ().isupper ();
+ t = i.next_char ();
+ bool next_upper = t.get_char ().isupper ();
+ if (!prev_upper || (i.len () >= 2 && !next_upper)) {
+ /* previous character wasn't upper case or
+ * next character isn't upper case*/
+ int len = result.str.len ();
+ if (len != 1 && result.str.offset (len - 2).get_char () != '_') {
+ /* we're not creating 1 character words */
+ result.append_c ('_');
+ }
+ }
+ }
+
+ result.append_unichar (c.tolower ());
+
+ first = false;
+ i = i.next_char ();
+ }
+
+ return result.str;
+ }
+
+ /**
+ * Returns the camel case string to be prepended to the name of members
+ * of this namespace when used in C code.
+ *
+ * @return the camel case prefix to be used in C code
+ */
+ public string! get_cprefix () {
+ if (cprefix == null) {
+ if (name == null) {
+ cprefix = "";
+ } else {
+ cprefix = name;
+ }
+ }
+ return cprefix;
+ }
+
+ private void set_cprefix (string cprefix) {
+ this.cprefix = cprefix;
+ }
+
+ /**
+ * Returns the lower case string to be prepended to the name of members
+ * of this namespace when used in C code.
+ *
+ * @return the lower case prefix to be used in C code
+ */
+ public string! get_lower_case_cprefix () {
+ if (lower_case_cprefix == null) {
+ if (name == null) {
+ lower_case_cprefix = "";
+ } else {
+ lower_case_cprefix = "%s_".printf (camel_case_to_lower_case (name));
+ }
+ }
+ return lower_case_cprefix;
+ }
+
+ private void set_lower_case_cprefix (string cprefix) {
+ this.lower_case_cprefix = cprefix;
+ }
+
+ /**
+ * Returns a list of C header filenames users of this namespace must
+ * include.
+ *
+ * @return list of C header filenames for this namespace
+ */
+ public ref List<weak string> get_cheader_filenames () {
+ if (cheader_filenames == null) {
+ cheader_filenames.append (source_reference.file.get_cinclude_filename ());
+ }
+ return cheader_filenames.copy ();
+ }
+
+ /**
+ * Returns the C header filename of this namespace.
+ *
+ * @return header filename
+ */
+ public ref string get_cheader_filename () {
+ var s = new String ();
+ bool first = true;
+ foreach (string cheader_filename in get_cheader_filenames ()) {
+ if (first) {
+ first = false;
+ } else {
+ s.append_c (',');
+ }
+ s.append (cheader_filename);
+ }
+ return s.str;
+ }
+
+ /**
+ * Sets the C header filename of this namespace to the specified
+ * filename.
+ *
+ * @param cheader_filename header filename
+ */
+ public void set_cheader_filename (string! cheader_filename) {
+ cheader_filenames = null;
+ cheader_filenames.append (cheader_filename);
+ }
+
+ private void process_ccode_attribute (Attribute! a) {
+ if (a.has_argument ("cprefix")) {
+ set_cprefix (a.get_string ("cprefix"));
+ }
+ if (a.has_argument ("lower_case_cprefix")) {
+ set_lower_case_cprefix (a.get_string ("lower_case_cprefix"));
+ }
+ if (a.has_argument ("cheader_filename")) {
+ var val = a.get_string ("cheader_filename");
+ foreach (string filename in val.split (",")) {
+ cheader_filenames.append (filename);
+ }
+ }
+ }
+
+ /**
+ * Process all associated attributes.
+ */
+ public void process_attributes () {
+ foreach (Attribute a in attributes) {
+ if (a.name == "CCode") {
+ process_ccode_attribute (a);
+ }
+ }
+ }
+}
diff --git a/vala/valanamespacereference.vala b/vala/valanamespacereference.vala
new file mode 100644
index 000000000..6b78b81fc
--- /dev/null
+++ b/vala/valanamespacereference.vala
@@ -0,0 +1,54 @@
+/* valanamespacereference.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;
+
+/**
+ * A reference to a namespace symbol.
+ */
+public class Vala.NamespaceReference : CodeNode {
+ /**
+ * The name of the namespace this reference is referring to.
+ */
+ public string! name { get; set construct; }
+
+ /**
+ * The resolved symbol of the namespace this reference is referring to.
+ */
+ public weak Symbol namespace_symbol { get; set; }
+
+ /**
+ * Creates a new namespace reference.
+ *
+ * @param name namespace name
+ * @param source reference to source code
+ * @return newly created namespace reference
+ */
+ public NamespaceReference (string! _name, SourceReference source) {
+ name = _name;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_namespace_reference (this);
+ }
+}
diff --git a/vala/valanullliteral.vala b/vala/valanullliteral.vala
new file mode 100644
index 000000000..0356d01cf
--- /dev/null
+++ b/vala/valanullliteral.vala
@@ -0,0 +1,46 @@
+/* valanullliteral.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;
+
+/**
+ * Represents a literal `null' in the source code.
+ */
+public class Vala.NullLiteral : Literal {
+ /**
+ * Creates a new null literal.
+ *
+ * @param source reference to source code
+ * @return newly created null literal
+ */
+ public NullLiteral (SourceReference source = null) {
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_null_literal (this);
+ }
+
+ public override ref string! to_string () {
+ return "null";
+ }
+}
diff --git a/vala/valaobjectcreationexpression.vala b/vala/valaobjectcreationexpression.vala
new file mode 100644
index 000000000..fa81d93a9
--- /dev/null
+++ b/vala/valaobjectcreationexpression.vala
@@ -0,0 +1,110 @@
+/* valaobjectcreationexpression.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;
+
+/**
+ * Represents an object creation expression in the source code.
+ */
+public class Vala.ObjectCreationExpression : Expression {
+ /**
+ * The object type to create.
+ */
+ public TypeReference type_reference { get; set; }
+
+ /**
+ * The construction method to use. May be null to indicate that
+ * the default construction method should be used.
+ */
+ public Method constructor { get; set; }
+
+ /**
+ * The construction method to use or the data type to be created
+ * with the default construction method.
+ */
+ public MemberAccess member_name { get; set; }
+
+ private List<Expression> argument_list;
+
+ /**
+ * Creates a new object creation expression.
+ *
+ * @param type object type to create
+ * @param source reference to source code
+ * @return newly created object creation expression
+ */
+ public ObjectCreationExpression (MemberAccess! name, SourceReference source) {
+ member_name = name;
+ source_reference = source;
+ }
+
+ /**
+ * Appends the specified expression to the list of arguments.
+ *
+ * @param arg an argument
+ */
+ public void add_argument (Expression! arg) {
+ argument_list.append (arg);
+ arg.parent_node = this;
+ }
+
+ /**
+ * Returns a copy of the argument list.
+ *
+ * @return argument list
+ */
+ public ref List<weak Expression> get_argument_list () {
+ return argument_list.copy ();
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ if (type_reference != null) {
+ type_reference.accept (visitor);
+ }
+
+ if (member_name != null) {
+ member_name.accept (visitor);
+ }
+
+ visitor.visit_begin_object_creation_expression (this);
+
+ // iterate over list copy as list may change in loop body
+ foreach (Expression arg in argument_list.copy ()) {
+ arg.accept (visitor);
+ }
+
+ visitor.visit_end_object_creation_expression (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ weak List<Expression> l = argument_list.find (old_node);
+ if (l != null) {
+ if (new_node.parent_node != null) {
+ return;
+ }
+
+ argument_list.insert_before (l, new_node);
+ argument_list.remove_link (l);
+ new_node.parent_node = this;
+ }
+ }
+}
diff --git a/vala/valaparenthesizedexpression.vala b/vala/valaparenthesizedexpression.vala
new file mode 100644
index 000000000..e26662665
--- /dev/null
+++ b/vala/valaparenthesizedexpression.vala
@@ -0,0 +1,67 @@
+/* valaparenthesizedexpression.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;
+
+/**
+ * Represents a parenthesized expression in the source code.
+ */
+public class Vala.ParenthesizedExpression : Expression {
+ /**
+ * The inner expression.
+ */
+ public Expression! inner {
+ get {
+ return _inner;
+ }
+ set construct {
+ _inner = value;
+ _inner.parent_node = this;
+ }
+ }
+
+ private Expression! _inner;
+
+ /**
+ * Creates a new parenthesized expression.
+ *
+ * @param inner an expression
+ * @param source reference to source code
+ * @return newly created parenthesized expression
+ */
+ public ParenthesizedExpression (Expression! _inner, SourceReference source) {
+ inner = _inner;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ inner.accept (visitor);
+
+ visitor.visit_parenthesized_expression (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (inner == old_node) {
+ inner = (Expression) new_node;
+ }
+ }
+}
diff --git a/vala/valaparser.vala b/vala/valaparser.vala
new file mode 100644
index 000000000..16144680b
--- /dev/null
+++ b/vala/valaparser.vala
@@ -0,0 +1,94 @@
+/* valaparser.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;
+
+/**
+ * Code visitor parsing all Vala source files.
+ */
+public class Vala.Parser : CodeVisitor {
+ private string comment;
+ private string _file_comment;
+
+ /**
+ * Parse all source files in the specified code context and build a
+ * code tree.
+ *
+ * @param context a code context
+ */
+ public void parse (CodeContext! context) {
+ context.accept (this);
+ }
+
+ public override void visit_begin_source_file (SourceFile! source_file) {
+ if (source_file.filename.has_suffix (".vala")) {
+ parse_file (source_file);
+ source_file.comment = _file_comment;
+ }
+ }
+
+ public override void visit_end_source_file (SourceFile! source_file) {
+ _file_comment = null;
+ }
+
+ /**
+ * Adds the specified comment to the comment stack.
+ *
+ * @param comment_item a comment string
+ * @param file_comment true if file header comment, false otherwise
+ */
+ public void push_comment (string! comment_item, bool file_comment) {
+ if (comment == null) {
+ comment = comment_item;
+ } else {
+ comment = "%s\n%s".printf (comment, comment_item);
+ }
+ if (file_comment) {
+ _file_comment = comment;
+ comment = null;
+ }
+ }
+
+ /**
+ * Clears and returns the content of the comment stack.
+ *
+ * @return saved comment
+ */
+ public ref string pop_comment () {
+ if (comment == null) {
+ return null;
+ }
+
+ String result = new String (comment);
+ comment = null;
+
+ weak string index;
+ while ((index = result.str.chr (-1, '\t')) != null) {
+ result.erase (result.str.pointer_to_offset (index), 1);
+ }
+
+ return result.str;
+ }
+
+ [Import ()]
+ public void parse_file (SourceFile! source_file);
+}
diff --git a/vala/valapointer.vala b/vala/valapointer.vala
new file mode 100644
index 000000000..12b3afea9
--- /dev/null
+++ b/vala/valapointer.vala
@@ -0,0 +1,90 @@
+/* valapointer.vala
+ *
+ * Copyright (C) 2007 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;
+
+/**
+ * Represents a pointer-type.
+ */
+public class Vala.Pointer : DataType {
+ /**
+ * The type to which this pointer type points.
+ */
+ public DataType! referent_type { get; set construct; }
+
+ private string cname;
+
+ public Pointer (construct DataType! referent_type, construct SourceReference source_reference = null) {
+ }
+
+ construct {
+ name = referent_type.name + "*";
+ }
+
+ public override string get_cname (bool const_type = false) {
+ if (cname == null) {
+ if (referent_type.is_reference_type ()) {
+ cname = "%s**".printf (referent_type.get_cname ());
+ } else {
+ cname = "%s*".printf (referent_type.get_cname ());
+ }
+ }
+
+ return cname;
+ }
+
+ public override bool is_reference_type () {
+ return false;
+ }
+
+ public override ref string get_upper_case_cname (string infix) {
+ return null;
+ }
+
+ public override ref string get_lower_case_cname (string infix) {
+ return null;
+ }
+
+ public override string get_free_function () {
+ return null;
+ }
+
+ public override ref List<string> get_cheader_filenames () {
+ return referent_type.get_cheader_filenames ();
+ }
+
+ public override string get_type_id () {
+ return "G_TYPE_POINTER";
+ }
+
+ public override string get_marshaller_type_name () {
+ return "POINTER";
+ }
+
+ public override string get_get_value_function () {
+ return "g_value_get_pointer";
+ }
+
+ public override string get_set_value_function () {
+ return "g_value_set_pointer";
+ }
+}
diff --git a/vala/valapointerindirection.vala b/vala/valapointerindirection.vala
new file mode 100644
index 000000000..747001e11
--- /dev/null
+++ b/vala/valapointerindirection.vala
@@ -0,0 +1,64 @@
+/* valapointerindirection.vala
+ *
+ * Copyright (C) 2007 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;
+
+/**
+ * Represents a pointer indirection in the source code, e.g. `*pointer'.
+ */
+public class Vala.PointerIndirection : Expression {
+ /**
+ * The pointer to dereference.
+ */
+ public Expression! inner {
+ get {
+ return _inner;
+ }
+ set construct {
+ _inner = value;
+ _inner.parent_node = this;
+ }
+ }
+
+ private Expression! _inner;
+
+ /**
+ * Creates a new pointer indirection.
+ *
+ * @param inner pointer to be dereferenced
+ * @return newly created pointer indirection
+ */
+ public PointerIndirection (construct Expression! inner, construct SourceReference source_reference = null) {
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ inner.accept (visitor);
+
+ visitor.visit_pointer_indirection (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (inner == old_node) {
+ inner = (Expression) new_node;
+ }
+ }
+}
diff --git a/vala/valapostfixexpression.vala b/vala/valapostfixexpression.vala
new file mode 100644
index 000000000..66ecbb71d
--- /dev/null
+++ b/vala/valapostfixexpression.vala
@@ -0,0 +1,58 @@
+/* valapostfixexpression.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;
+
+/**
+ * Represents a postfix increment or decrement expression.
+ */
+public class Vala.PostfixExpression : Expression {
+ /**
+ * The operand, must be a variable or a property.
+ */
+ public Expression! inner { get; set construct; }
+
+ /**
+ * Specifies whether value should be incremented or decremented.
+ */
+ public bool increment { get; set; }
+
+ /**
+ * Creates a new postfix expression.
+ *
+ * @param inner operand expression
+ * @param inc true for increment, false for decrement
+ * @param source reference to source code
+ * @return newly created postfix expression
+ */
+ public PostfixExpression (Expression! _inner, bool inc, SourceReference source) {
+ inner = _inner;
+ increment = inc;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ inner.accept (visitor);
+
+ visitor.visit_postfix_expression (this);
+ }
+}
diff --git a/vala/valaproperty.vala b/vala/valaproperty.vala
new file mode 100644
index 000000000..16b5b29bb
--- /dev/null
+++ b/vala/valaproperty.vala
@@ -0,0 +1,231 @@
+/* valaproperty.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * Represents a property declaration in the source code.
+ */
+public class Vala.Property : Member, Lockable {
+ /**
+ * The property name.
+ */
+ public string! name { get; set construct; }
+
+ /**
+ * The property type.
+ */
+ public TypeReference! type_reference { get; set construct; }
+
+ /**
+ * The get accessor of this property if available.
+ */
+ public PropertyAccessor get_accessor { get; set; }
+
+ /**
+ * The set/construct accessor of this property if available.
+ */
+ public PropertyAccessor set_accessor { get; set; }
+
+ /**
+ * Specifies the accessibility of this property. Public accessibility
+ * doesn't limit access. Default accessibility limits access to this
+ * program or library. Private accessibility limits access to the parent
+ * class.
+ */
+ public MemberAccessibility access { get; set; }
+
+ /**
+ * Represents the generated ´this' parameter in this property.
+ */
+ public FormalParameter this_parameter { get; set; }
+
+ /**
+ * Specifies whether the implementation of this property does not
+ * provide getter/setter methods.
+ */
+ public bool no_accessor_method { get; set; }
+
+ /**
+ * Specifies whether automatic accessor code generation should be
+ * disabled.
+ */
+ public bool interface_only { get; set; }
+
+ /**
+ * Specifies whether this property is abstract. Abstract properties have
+ * no accessor bodies, may only be specified within abstract classes and
+ * interfaces, and must be overriden by derived non-abstract classes.
+ */
+ public bool is_abstract { get; set; }
+
+ /**
+ * Specifies whether this property is virtual. Virtual properties may be
+ * overridden by derived classes.
+ */
+ public bool is_virtual { get; set; }
+
+ /**
+ * Specifies whether this property overrides a virtual or abstract
+ * property of a base type.
+ */
+ public bool overrides { get; set; }
+
+ /**
+ * Specifies the virtual or abstract property this property overrides.
+ * Reference must be weak as virtual properties set base_property to
+ * themselves.
+ */
+ public weak Property base_property { get; set; }
+
+ /**
+ * Specifies the abstract interface property this property implements.
+ */
+ public Property base_interface_property { get; set; }
+
+ private bool lock_used = false;
+
+ /**
+ * Creates a new property.
+ *
+ * @param name property name
+ * @param type property type
+ * @param get_accessor get accessor
+ * @param set_accessor set/construct accessor
+ * @param source reference to source code
+ * @return newly created property
+ */
+ public Property (string! _name, TypeReference! type, PropertyAccessor _get_accessor, PropertyAccessor _set_accessor, SourceReference source) {
+ name = _name;
+ type_reference = type;
+ get_accessor = _get_accessor;
+ set_accessor = _set_accessor;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_member (this);
+ visitor.visit_begin_property (this);
+
+ type_reference.accept (visitor);
+
+ if (get_accessor != null) {
+ get_accessor.accept (visitor);
+ }
+ if (set_accessor != null) {
+ set_accessor.accept (visitor);
+ }
+
+ visitor.visit_end_property (this);
+ }
+
+ /**
+ * Returns the C name of this property in upper case. Words are
+ * separated by underscores. The upper case C name of the class is
+ * prefix of the result.
+ *
+ * @return the upper case name to be used in C code
+ */
+ public ref string! get_upper_case_cname () {
+ return "%s_%s".printf (((DataType) symbol.parent_symbol.node).get_lower_case_cname (null), Namespace.camel_case_to_lower_case (name)).up ();
+ }
+
+ /**
+ * Returns the string literal of this property to be used in C code.
+ *
+ * @return string literal to be used in C code
+ */
+ public ref CCodeConstant! get_canonical_cconstant () {
+ var str = new String ("\"");
+
+ string i = name;
+
+ while (i.len () > 0) {
+ unichar c = i.get_char ();
+ if (c == '_') {
+ str.append_c ('-');
+ } else {
+ str.append_unichar (c);
+ }
+
+ i = i.next_char ();
+ }
+
+ str.append_c ('"');
+
+ return new CCodeConstant (str.str);
+ }
+
+ /**
+ * Process all associated attributes.
+ */
+ public void process_attributes () {
+ foreach (Attribute a in attributes) {
+ if (a.name == "NoAccessorMethod") {
+ no_accessor_method = true;
+ }
+ }
+ }
+
+ public bool get_lock_used () {
+ return lock_used;
+ }
+
+ public void set_lock_used (bool used) {
+ lock_used = used;
+ }
+
+ /**
+ * Checks whether the accessors and type of the specified property
+ * matches this property.
+ *
+ * @param prop a property
+ * @return true if the specified property is compatible to this
+ * property
+ */
+ public bool equals (Property! prop2) {
+ if (!prop2.type_reference.equals (type_reference)) {
+ return false;
+ }
+
+ if ((get_accessor == null && prop2.get_accessor != null) ||
+ (get_accessor != null && prop2.get_accessor == null)) {
+ return false;
+ }
+
+ if ((set_accessor == null && prop2.set_accessor != null) ||
+ (set_accessor != null && prop2.set_accessor == null)) {
+ return false;
+ }
+
+ if (set_accessor != null) {
+ if (set_accessor.writable != prop2.set_accessor.writable) {
+ return false;
+ }
+ if (set_accessor.construction != prop2.set_accessor.construction) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/vala/valapropertyaccessor.vala b/vala/valapropertyaccessor.vala
new file mode 100644
index 000000000..3177aa5d7
--- /dev/null
+++ b/vala/valapropertyaccessor.vala
@@ -0,0 +1,82 @@
+/* valapropertyaccessor.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;
+
+/**
+ * Represents a get or set accessor of a property in the source code.
+ */
+public class Vala.PropertyAccessor : CodeNode {
+ /**
+ * Specifies whether this accessor may be used to get the property.
+ */
+ public bool readable { get; set; }
+
+ /**
+ * Specifies whether this accessor may be used to set the property.
+ */
+ public bool writable { get; set; }
+
+ /**
+ * Specifies whether this accessor may be used to construct the
+ * property.
+ */
+ public bool construction { get; set; }
+
+ /**
+ * The accessor body.
+ */
+ public Statement body { get; set; }
+
+ /**
+ * Represents the generated value parameter in a set accessor.
+ */
+ public FormalParameter value_parameter { get; set; }
+
+ /**
+ * Creates a new property accessor.
+ *
+ * @param readable true if get accessor, false otherwise
+ * @param writable true if set accessor, false otherwise
+ * @param construction true if construct accessor, false otherwise
+ * @param body accessor body
+ * @param source reference to source code
+ * @return newly created property accessor
+ */
+ public PropertyAccessor (bool _readable, bool _writable, bool _construction, Statement _body, SourceReference source) {
+ readable = _readable;
+ writable = _writable;
+ construction = _construction;
+ body = _body;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_property_accessor (this);
+
+ if (body != null) {
+ body.accept (visitor);
+ }
+
+ visitor.visit_end_property_accessor (this);
+ }
+}
diff --git a/vala/valarealliteral.vala b/vala/valarealliteral.vala
new file mode 100644
index 000000000..a85cf2073
--- /dev/null
+++ b/vala/valarealliteral.vala
@@ -0,0 +1,62 @@
+/* valarealliteral.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;
+
+/**
+ * Represents a real literal in the source code.
+ */
+public class Vala.RealLiteral : Literal {
+ /**
+ * The literal value.
+ */
+ public string value { get; set; }
+
+ /**
+ * Creates a new real literal.
+ *
+ * @param r literal value
+ * @param source reference to source code
+ * @return newly created real literal
+ */
+ public RealLiteral (string r, SourceReference source) {
+ value = r;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_real_literal (this);
+ }
+
+ /**
+ * Returns the type name of the value this literal represents.
+ *
+ * @return the name of literal type
+ */
+ public string! get_type_name () {
+ if (value.has_suffix ("F")) {
+ return "float";
+ }
+
+ return "double";
+ }
+}
diff --git a/vala/valareferencetransferexpression.vala b/vala/valareferencetransferexpression.vala
new file mode 100644
index 000000000..ec6000d09
--- /dev/null
+++ b/vala/valareferencetransferexpression.vala
@@ -0,0 +1,64 @@
+/* valareferencetransferexpression.vala
+ *
+ * Copyright (C) 2007 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;
+
+/**
+ * Represents a reference transfer expression in the source code, e.g. `#foo'.
+ */
+public class Vala.ReferenceTransferExpression : Expression {
+ /**
+ * The variable whose reference is to be transferred.
+ */
+ public Expression! inner {
+ get {
+ return _inner;
+ }
+ set construct {
+ _inner = value;
+ _inner.parent_node = this;
+ }
+ }
+
+ private Expression! _inner;
+
+ /**
+ * Creates a new reference transfer expression.
+ *
+ * @param inner variable whose reference is to be transferred
+ * @return newly created reference transfer expression
+ */
+ public ReferenceTransferExpression (construct Expression! inner, construct SourceReference source_reference = null) {
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ inner.accept (visitor);
+
+ visitor.visit_reference_transfer_expression (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (inner == old_node) {
+ inner = (Expression) new_node;
+ }
+ }
+}
diff --git a/vala/valareport.vala b/vala/valareport.vala
new file mode 100644
index 000000000..8936fbb21
--- /dev/null
+++ b/vala/valareport.vala
@@ -0,0 +1,75 @@
+/* valareport.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;
+
+/**
+ * Static class to centralize reporting warnings and errors.
+ */
+public class Vala.Report {
+ private static int warnings;
+ private static int errors;
+
+ /**
+ * Returns the total number of warnings reported.
+ */
+ public static int get_warnings () {
+ return warnings;
+ }
+
+ /**
+ * Returns the total number of errors reported.
+ */
+ public static int get_errors () {
+ return errors;
+ }
+
+ /**
+ * Reports the specified message as warning.
+ *
+ * @param source reference to source code
+ * @param message warning message
+ */
+ public static void warning (SourceReference source, string! message) {
+ warnings++;
+ if (source == null) {
+ stderr.printf ("warning: %s\n", message);
+ } else {
+ stderr.printf ("%s: warning: %s\n", source.to_string (), message);
+ }
+ }
+
+ /**
+ * Reports the specified message as error.
+ *
+ * @param source reference to source code
+ * @param message error message
+ */
+ public static void error (SourceReference source, string! message) {
+ errors++;
+ if (source == null) {
+ stderr.printf ("error: %s\n", message);
+ } else {
+ stderr.printf ("%s: error: %s\n", source.to_string (), message);
+ }
+ }
+}
diff --git a/vala/valareturnstatement.vala b/vala/valareturnstatement.vala
new file mode 100644
index 000000000..52e7b0841
--- /dev/null
+++ b/vala/valareturnstatement.vala
@@ -0,0 +1,75 @@
+/* valareturnstatement.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;
+
+/**
+ * Represents a return statement in the source code.
+ */
+public class Vala.ReturnStatement : Statement {
+ /**
+ * The optional expression to return.
+ */
+ public Expression return_expression {
+ get {
+ return _return_expression;
+ }
+ set {
+ _return_expression = value;
+ if (_return_expression != null) {
+ _return_expression.parent_node = this;
+ }
+ }
+ }
+
+ private Expression! _return_expression;
+
+ /**
+ * Creates a new return statement.
+ *
+ * @param result the return expression
+ * @param source reference to source code
+ * @return newly created return statement
+ */
+ public ReturnStatement (Expression result = null, SourceReference source = null) {
+ return_expression = result;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_return_statement (this);
+
+ if (return_expression != null) {
+ return_expression.accept (visitor);
+
+ visitor.visit_end_full_expression (return_expression);
+ }
+
+ visitor.visit_end_return_statement (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (return_expression == old_node) {
+ return_expression = (Expression) new_node;
+ }
+ }
+}
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala
new file mode 100644
index 000000000..4b03fa61e
--- /dev/null
+++ b/vala/valasemanticanalyzer.vala
@@ -0,0 +1,2341 @@
+/* valasemanticanalyzer.vala
+ *
+ * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
+ *
+ * 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>
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+using GLib;
+
+/**
+ * Code visitor analyzing and checking code.
+ */
+public class Vala.SemanticAnalyzer : CodeVisitor {
+ /**
+ * Specifies whether automatic memory management is active.
+ */
+ public bool memory_management { get; set; }
+
+ Symbol root_symbol;
+ Symbol current_symbol;
+ SourceFile current_source_file;
+ TypeReference current_return_type;
+ Class current_class;
+ Struct current_struct;
+
+ List<weak NamespaceReference> current_using_directives;
+
+ TypeReference bool_type;
+ TypeReference string_type;
+ TypeReference int_type;
+ TypeReference uint_type;
+ TypeReference type_type;
+ DataType pointer_type;
+ DataType initially_unowned_type;
+ DataType glist_type;
+ DataType gslist_type;
+
+ private int next_lambda_id = 0;
+
+ public SemanticAnalyzer (bool manage_memory = true) {
+ memory_management = manage_memory;
+ }
+
+ /**
+ * Analyze and check code in the specified context.
+ *
+ * @param context a code context
+ */
+ public void analyze (CodeContext! context) {
+ root_symbol = context.get_root ();
+
+ bool_type = new TypeReference ();
+ bool_type.data_type = (DataType) root_symbol.lookup ("bool").node;
+
+ string_type = new TypeReference ();
+ string_type.data_type = (DataType) root_symbol.lookup ("string").node;
+
+ pointer_type = (DataType) root_symbol.lookup ("pointer").node;
+
+ int_type = new TypeReference ();
+ int_type.data_type = (DataType) root_symbol.lookup ("int").node;
+
+ uint_type = new TypeReference ();
+ uint_type.data_type = (DataType) root_symbol.lookup ("uint").node;
+
+ // TODO: don't require GLib namespace in semantic analyzer
+ var glib_ns = root_symbol.lookup ("GLib");
+ if (glib_ns != null) {
+ initially_unowned_type = (DataType) glib_ns.lookup ("InitiallyUnowned").node;
+
+ type_type = new TypeReference ();
+ type_type.data_type = (DataType) glib_ns.lookup ("Type").node;
+
+ glist_type = (DataType) glib_ns.lookup ("List").node;
+ gslist_type = (DataType) glib_ns.lookup ("SList").node;
+ }
+
+ current_symbol = root_symbol;
+ context.accept (this);
+ }
+
+ public override void visit_begin_source_file (SourceFile! file) {
+ current_source_file = file;
+ current_using_directives = file.get_using_directives ();
+
+ next_lambda_id = 0;
+ }
+
+ public override void visit_end_source_file (SourceFile! file) {
+ current_using_directives = null;
+ }
+
+ public override void visit_begin_namespace (Namespace! ns) {
+ current_symbol = ns.symbol;
+ }
+
+ public override void visit_end_namespace (Namespace! ns) {
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_begin_class (Class! cl) {
+ current_symbol = cl.symbol;
+ current_class = cl;
+
+ if (cl.base_class != null) {
+ current_source_file.add_symbol_dependency (cl.base_class.symbol, SourceFileDependencyType.HEADER_FULL);
+ }
+
+ foreach (TypeReference base_type_reference in cl.get_base_types ()) {
+ current_source_file.add_symbol_dependency (base_type_reference.data_type.symbol, SourceFileDependencyType.HEADER_FULL);
+ }
+ }
+
+ private ref List<DataType> get_all_prerequisites (Interface! iface) {
+ List<DataType> ret = null;
+
+ foreach (TypeReference prereq in iface.get_prerequisites ()) {
+ DataType type = prereq.data_type;
+ /* skip on previous errors */
+ if (type == null) {
+ continue;
+ }
+
+ ret.prepend (type);
+ if (type is Interface) {
+ ret.concat (get_all_prerequisites ((Interface) type));
+
+ }
+ }
+
+ ret.reverse ();
+ return #ret;
+ }
+
+ private bool class_is_a (Class! cl, DataType! t) {
+ if (cl == t) {
+ return true;
+ }
+
+ foreach (TypeReference base_type in cl.get_base_types ()) {
+ if (base_type.data_type is Class) {
+ if (class_is_a ((Class) base_type.data_type, t)) {
+ return true;
+ }
+ } else if (base_type.data_type == t) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public override void visit_end_class (Class! cl) {
+ /* gather all prerequisites */
+ List<DataType> prerequisites = null;
+ foreach (TypeReference base_type in cl.get_base_types ()) {
+ if (base_type.data_type is Interface) {
+ prerequisites.concat (get_all_prerequisites ((Interface) base_type.data_type));
+ }
+ }
+ /* check whether all prerequisites are met */
+ List<string> missing_prereqs = null;
+ foreach (DataType prereq in prerequisites) {
+ if (!class_is_a (cl, prereq)) {
+ missing_prereqs.prepend (prereq.symbol.get_full_name ());
+ }
+ }
+ /* report any missing prerequisites */
+ if (missing_prereqs != null) {
+ cl.error = true;
+
+ string error_string = "%s: some prerequisites (".printf (cl.symbol.get_full_name ());
+ bool first = true;
+ foreach (string s in missing_prereqs) {
+ if (first) {
+ error_string = "%s`%s'".printf (error_string, s);
+ first = false;
+ } else {
+ error_string = "%s, `%s'".printf (error_string, s);
+ }
+ }
+ error_string += ") are not met";
+ Report.error (cl.source_reference, error_string);
+ }
+
+ /* all abstract symbols defined in base types have to be at least defined (or implemented) also in this type */
+ foreach (TypeReference base_type in cl.get_base_types ()) {
+ if (base_type.data_type is Interface) {
+ Interface iface = (Interface) base_type.data_type;
+
+ /* We do not need to do expensive equality checking here since this is done
+ * already. We only need to guarantee the symbols are present.
+ */
+
+ /* check methods */
+ foreach (Method m in iface.get_methods ()) {
+ if (m.is_abstract) {
+ var sym = cl.symbol.lookup (m.name);
+ if (sym == null || !(sym.node is Method) || ((Method) sym.node).base_interface_method != m) {
+ cl.error = true;
+ Report.error (cl.source_reference, "`%s' does not implement interface method `%s'".printf (cl.symbol.get_full_name (), m.symbol.get_full_name ()));
+ }
+ }
+ }
+ }
+ }
+
+ /* all abstract symbols defined in base classes have to be implemented in non-abstract classes
+ * VAPI classes don't have to specify overridden methods
+ */
+ if (!cl.is_abstract && !cl.source_reference.file.pkg) {
+ var base_class = cl.base_class;
+ while (base_class != null && base_class.is_abstract) {
+ foreach (Method m in base_class.get_methods ()) {
+ if (m.is_abstract) {
+ var sym = cl.symbol.lookup (m.name);
+ if (sym == null || !(sym.node is Method) || ((Method) sym.node).base_method != m) {
+ cl.error = true;
+ Report.error (cl.source_reference, "`%s' does not implement abstract method `%s'".printf (cl.symbol.get_full_name (), m.symbol.get_full_name ()));
+ }
+ }
+ }
+ base_class = base_class.base_class;
+ }
+ }
+
+ current_symbol = current_symbol.parent_symbol;
+ current_class = null;
+ }
+
+ public override void visit_begin_struct (Struct! st) {
+ current_symbol = st.symbol;
+ current_struct = st;
+ }
+
+ public override void visit_end_struct (Struct! st) {
+ current_symbol = current_symbol.parent_symbol;
+ current_struct = null;
+ }
+
+ public override void visit_begin_interface (Interface! iface) {
+ current_symbol = iface.symbol;
+
+ foreach (TypeReference prerequisite_reference in iface.get_prerequisites ()) {
+ current_source_file.add_symbol_dependency (prerequisite_reference.data_type.symbol, SourceFileDependencyType.HEADER_FULL);
+ }
+ }
+
+ public override void visit_end_interface (Interface! iface) {
+ /* check prerequisites */
+ Class prereq_class;
+ foreach (TypeReference prereq in iface.get_prerequisites ()) {
+ DataType class_or_interface = prereq.data_type;
+ /* skip on previous errors */
+ if (class_or_interface == null) {
+ iface.error = true;
+ continue;
+ }
+ /* interfaces are not allowed to have multiple instantiable prerequisites */
+ if (class_or_interface is Class) {
+ if (prereq_class != null) {
+ iface.error = true;
+ Report.error (iface.source_reference, "%s: Interfaces cannot have multiple instantiable prerequisites (`%s' and `%s')".printf (iface.symbol.get_full_name (), class_or_interface.symbol.get_full_name (), prereq_class.symbol.get_full_name ()));
+ return;
+ }
+
+ prereq_class = (Class)class_or_interface;
+ }
+ }
+
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_constant (Constant! c) {
+ if (!current_source_file.pkg) {
+ if (c.initializer == null) {
+ c.error = true;
+ Report.error (c.source_reference, "A const field requires a initializer to be provided");
+ }
+ }
+ }
+
+ public override void visit_field (Field! f) {
+ if (f.access != MemberAccessibility.PRIVATE) {
+ if (f.type_reference.data_type != null) {
+ /* is null if it references a type parameter */
+ current_source_file.add_symbol_dependency (f.type_reference.data_type.symbol, SourceFileDependencyType.HEADER_SHALLOW);
+ }
+ } else {
+ if (f.type_reference.data_type != null) {
+ /* is null if it references a type parameter */
+ current_source_file.add_symbol_dependency (f.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE);
+ }
+ }
+ }
+
+ public override void visit_begin_method (Method! m) {
+ current_symbol = m.symbol;
+ current_return_type = m.return_type;
+
+ var init_attr = m.get_attribute ("ModuleInit");
+ if (init_attr != null) {
+ m.source_reference.file.context.module_init_method = m;
+ }
+
+ if (m.return_type.data_type != null) {
+ /* is null if it is void or a reference to a type parameter */
+ current_source_file.add_symbol_dependency (m.return_type.data_type.symbol, SourceFileDependencyType.HEADER_SHALLOW);
+ }
+ }
+
+ private void find_base_class_method (Method! m, Class! cl) {
+ var sym = cl.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) {
+ if (!m.equals (base_method)) {
+ m.error = true;
+ Report.error (m.source_reference, "Return type and/or parameters of overriding method `%s' do not match overridden method `%s'.".printf (m.symbol.get_full_name (), base_method.symbol.get_full_name ()));
+ return;
+ }
+
+ m.base_method = base_method;
+ return;
+ }
+ }
+
+ if (cl.base_class != null) {
+ find_base_class_method (m, cl.base_class);
+ }
+ }
+
+ private void find_base_interface_method (Method! m, Class! cl) {
+ // FIXME report error if multiple possible base methods are found
+ foreach (TypeReference type in cl.get_base_types ()) {
+ if (type.data_type is Interface) {
+ var sym = type.data_type.symbol.lookup (m.name);
+ if (sym != null && sym.node is Method) {
+ var base_method = (Method) sym.node;
+ if (base_method.is_abstract) {
+ if (!m.equals (base_method)) {
+ m.error = true;
+ Report.error (m.source_reference, "Return type and/or parameters of overriding method `%s' do not match overridden method `%s'.".printf (m.symbol.get_full_name (), base_method.symbol.get_full_name ()));
+ return;
+ }
+
+ m.base_interface_method = base_method;
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ public override void visit_end_method (Method! m) {
+ current_symbol = current_symbol.parent_symbol;
+ current_return_type = null;
+
+ if (current_symbol.parent_symbol != null &&
+ current_symbol.parent_symbol.node is Method) {
+ /* lambda expressions produce nested methods */
+ var up_method = (Method) current_symbol.parent_symbol.node;
+ current_return_type = up_method.return_type;
+ }
+
+ if (current_symbol.node is Class) {
+ if (!(m is CreationMethod)) {
+ find_base_interface_method (m, (Class) current_symbol.node);
+ if (m.is_virtual || m.overrides) {
+ find_base_class_method (m, (Class) current_symbol.node);
+ if (m.base_method == null) {
+ Report.error (m.source_reference, "%s: no suitable method found to override".printf (m.symbol.get_full_name ()));
+ }
+ }
+ }
+ } else if (current_symbol.node is Struct) {
+ if (m.is_abstract || m.is_virtual || m.overrides) {
+ Report.error (m.source_reference, "A struct member `%s' cannot be marked as override, virtual, or abstract".printf (m.symbol.get_full_name ()));
+ return;
+ }
+ }
+ }
+
+ public override void visit_begin_creation_method (CreationMethod! m) {
+ m.return_type = new TypeReference ();
+ m.return_type.data_type = (DataType) current_symbol.node;
+ m.return_type.transfers_ownership = true;
+
+ if (current_symbol.node is Class) {
+ // check for floating reference
+ var cl = (Class) current_symbol.node;
+ while (cl != null) {
+ if (cl == initially_unowned_type) {
+ m.return_type.floating_reference = true;
+ break;
+ }
+
+ cl = cl.base_class;
+ }
+ }
+
+ current_symbol = m.symbol;
+ current_return_type = m.return_type;
+ }
+
+ public override void visit_end_creation_method (CreationMethod! m) {
+ visit_end_method (m);
+
+ if (m.body != null && current_class != null) {
+ int n_params = 0;
+ foreach (Statement stmt in m.body.get_statements ()) {
+ int params = stmt.get_number_of_set_construction_parameters ();
+ if (params == -1) {
+ m.error = true;
+ Report.error (stmt.source_reference, "class creation methods only allow property assignment statements");
+ return;
+ }
+ n_params += params;
+ }
+ m.n_construction_params = n_params;
+ }
+ }
+
+ public override void visit_formal_parameter (FormalParameter! p) {
+ if (!p.ellipsis) {
+ if (p.type_reference.data_type != null) {
+ /* is null if it references a type parameter */
+ current_source_file.add_symbol_dependency (p.type_reference.data_type.symbol, SourceFileDependencyType.HEADER_SHALLOW);
+ current_source_file.add_symbol_dependency (p.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE);
+ }
+ }
+
+ /* special treatment for construct formal parameters used in creation methods */
+ if (p.construct_parameter) {
+ if (!(p.symbol.parent_symbol.node is CreationMethod)) {
+ p.error = true;
+ Report.error (p.source_reference, "construct parameters are only allowed in type creation methods");
+ return;
+ }
+
+ var method_body = ((CreationMethod)p.symbol.parent_symbol.node).body;
+ var left = new MemberAccess.simple (p.name);
+ var right = new MemberAccess.simple (p.name);
+
+ /* try to lookup the requested property */
+ var prop_sym = symbol_lookup_inherited (current_class.symbol, p.name);
+ if (!(prop_sym.node is Property)) {
+ p.error = true;
+ Report.error (p.source_reference, "class `%s' does not contain a property named `%s'".printf (current_class.symbol.get_full_name (), p.name));
+ return;
+ }
+ left.symbol_reference = prop_sym;
+
+ right.symbol_reference = p.symbol;
+
+ method_body.add_statement (new ExpressionStatement (new Assignment (left, right)));
+ }
+ }
+
+ private void find_base_class_property (Property! prop, Class! cl) {
+ var sym = cl.symbol.lookup (prop.name);
+ if (sym != null && sym.node is Property) {
+ var base_property = (Property) sym.node;
+ if (base_property.is_abstract || base_property.is_virtual) {
+ if (!prop.equals (base_property)) {
+ prop.error = true;
+ Report.error (prop.source_reference, "Type and/or accessors of overriding property `%s' do not match overridden property `%s'.".printf (prop.symbol.get_full_name (), base_property.symbol.get_full_name ()));
+ return;
+ }
+
+ prop.base_property = base_property;
+ return;
+ }
+ }
+
+ if (cl.base_class != null) {
+ find_base_class_property (prop, cl.base_class);
+ }
+ }
+
+ private void find_base_interface_property (Property! prop, Class! cl) {
+ // FIXME report error if multiple possible base properties are found
+ foreach (TypeReference type in cl.get_base_types ()) {
+ if (type.data_type is Interface) {
+ var sym = type.data_type.symbol.lookup (prop.name);
+ if (sym != null && sym.node is Property) {
+ var base_property = (Property) sym.node;
+ if (base_property.is_abstract) {
+ if (!prop.equals (base_property)) {
+ prop.error = true;
+ Report.error (prop.source_reference, "Type and/or accessors of overriding property `%s' do not match overridden property `%s'.".printf (prop.symbol.get_full_name (), base_property.symbol.get_full_name ()));
+ return;
+ }
+
+ prop.base_interface_property = base_property;
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ public override void visit_end_property (Property! prop) {
+ if (prop.type_reference.data_type != null) {
+ /* is null if it references a type parameter */
+ current_source_file.add_symbol_dependency (prop.type_reference.data_type.symbol, SourceFileDependencyType.HEADER_SHALLOW);
+ current_source_file.add_symbol_dependency (prop.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE);
+ }
+
+ if (prop.symbol.parent_symbol.node is Class) {
+ var cl = (Class) prop.symbol.parent_symbol.node;
+ find_base_interface_property (prop, cl);
+ if (prop.is_virtual || prop.overrides) {
+ find_base_class_property (prop, cl);
+ if (prop.base_property == null) {
+ prop.error = true;
+ Report.error (prop.source_reference, "%s: no suitable property found to override".printf (prop.symbol.get_full_name ()));
+ }
+ }
+ }
+ }
+
+ public override void visit_begin_property_accessor (PropertyAccessor! acc) {
+ var prop = (Property) acc.symbol.parent_symbol.node;
+
+ if (acc.readable) {
+ current_return_type = prop.type_reference;
+ } else {
+ // void
+ current_return_type = new TypeReference ();
+ }
+ }
+
+ public override void visit_end_property_accessor (PropertyAccessor! acc) {
+ current_return_type = null;
+ }
+
+ public override void visit_begin_constructor (Constructor! c) {
+ current_symbol = c.symbol;
+ }
+
+ public override void visit_end_constructor (Constructor! c) {
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_begin_destructor (Destructor! d) {
+ current_symbol = d.symbol;
+ }
+
+ public override void visit_end_destructor (Destructor! d) {
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_named_argument (NamedArgument! n) {
+ }
+
+ public override void visit_begin_block (Block! b) {
+ current_symbol = b.symbol;
+ }
+
+ public override void visit_end_block (Block! b) {
+ foreach (VariableDeclarator decl in b.get_local_variables ()) {
+ decl.symbol.active = false;
+ }
+
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_variable_declarator (VariableDeclarator! decl) {
+ if (decl.type_reference == null) {
+ /* var type */
+
+ if (decl.initializer == null) {
+ decl.error = true;
+ Report.error (decl.source_reference, "var declaration not allowed without initializer");
+ return;
+ }
+ if (decl.initializer.static_type == null) {
+ decl.error = true;
+ Report.error (decl.source_reference, "var declaration not allowed with non-typed initializer");
+ return;
+ }
+
+ decl.type_reference = decl.initializer.static_type.copy ();
+ decl.type_reference.takes_ownership = (decl.type_reference.data_type == null || decl.type_reference.data_type.is_reference_type ());
+ decl.type_reference.transfers_ownership = false;
+ }
+
+ if (decl.initializer != null) {
+ if (decl.initializer.static_type == null) {
+ if (!(decl.initializer is MemberAccess)) {
+ decl.error = true;
+ Report.error (decl.source_reference, "expression type not allowed as initializer");
+ return;
+ }
+
+ if (decl.initializer.symbol_reference.node is Method &&
+ decl.type_reference.data_type is Callback) {
+ var m = (Method) decl.initializer.symbol_reference.node;
+ var cb = (Callback) decl.type_reference.data_type;
+
+ /* check whether method matches callback type */
+ if (!cb.matches_method (m)) {
+ decl.error = true;
+ Report.error (decl.source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.symbol.get_full_name (), cb.symbol.get_full_name ()));
+ return;
+ }
+
+ decl.initializer.static_type = decl.type_reference;
+ } else {
+ decl.error = true;
+ Report.error (decl.source_reference, "expression type not allowed as initializer");
+ return;
+ }
+ }
+
+ if (memory_management) {
+ if (decl.initializer.static_type.transfers_ownership) {
+ /* rhs transfers ownership of the expression */
+ if (!decl.type_reference.takes_ownership) {
+ /* lhs doesn't own the value */
+ decl.error = true;
+ Report.error (decl.source_reference, "Invalid assignment from owned expression to unowned variable");
+ return;
+ }
+ }
+ }
+ }
+
+ if (decl.type_reference.data_type != null) {
+ current_source_file.add_symbol_dependency (decl.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE);
+ }
+
+ decl.symbol = new Symbol (decl);
+ current_symbol.add (decl.name, decl.symbol);
+
+ var block = (Block) current_symbol.node;
+ block.add_local_variable (decl);
+
+ decl.symbol.active = true;
+ }
+
+ /**
+ * Visit operation called for initializer lists
+ *
+ * @param list an initializer list
+ */
+ public override void visit_begin_initializer_list (InitializerList! list) {
+ if (list.expected_type != null && list.expected_type.data_type is Array) {
+ /* initializer is used as array initializer */
+ Array edt = (Array)list.expected_type.data_type;
+ var inits = list.get_initializers ();
+ int rank = ((Array)list.expected_type.data_type).rank;
+ var child_type = list.expected_type.copy ();
+
+ if (rank > 1) {
+ child_type.data_type = edt.element_type.get_array (rank - 1);
+ } else {
+ child_type.data_type = edt.element_type;
+ }
+
+ foreach (Expression e in inits) {
+ e.expected_type = child_type.copy ();
+ }
+ }
+ }
+
+ /**
+ * Visit operation called for initializer lists
+ *
+ * @param list an initializer list
+ */
+ public override void visit_end_initializer_list (InitializerList! list) {
+ if (list.expected_type != null && list.expected_type.data_type is Array) {
+ Array edt = (Array)list.expected_type.data_type;
+ var inits = list.get_initializers ();
+ int rank = edt.rank;
+ var child_type = list.expected_type.copy ();
+ bool error = false;
+
+ if (rank > 1) {
+ child_type.data_type = edt.element_type.get_array (rank - 1);
+ foreach (Expression e in inits) {
+ if (e.static_type == null) {
+ error = true;
+ continue;
+ }
+ if (!(e is InitializerList)) {
+ error = true;
+ e.error = true;
+ Report.error (e.source_reference, "Initializer list expected");
+ continue;
+ }
+ if (!e.static_type.equals (child_type)) {
+ error = true;
+ e.error = true;
+ Report.error (e.source_reference, "Expected initializer list of type `%s' but got `%s'".printf (child_type.data_type.name, e.static_type.data_type.name));
+ }
+ }
+ } else {
+ child_type.data_type = edt.element_type;
+ foreach (Expression e in inits) {
+ if (e.static_type == null) {
+ error = true;
+ continue;
+ }
+ if (!is_type_compatible (e.static_type, child_type)) {
+ error = true;
+ e.error = true;
+ Report.error (e.source_reference, "Expected initializer of type `%s' but got `%s'".printf (child_type.data_type.name, e.static_type.data_type.name));
+ }
+ }
+ }
+
+ if (!error) {
+ /* everything seems to be correct */
+ list.static_type = list.expected_type;
+ }
+ }
+ }
+
+ public override void visit_expression_statement (ExpressionStatement! stmt) {
+ if (stmt.expression.static_type != null &&
+ stmt.expression.static_type.transfers_ownership) {
+ Report.warning (stmt.source_reference, "Short-living reference");
+ return;
+ }
+ }
+
+ public override void visit_if_statement (IfStatement! stmt) {
+ if (stmt.condition.error) {
+ /* if there was an error in the condition, skip this check */
+ stmt.error = true;
+ return;
+ }
+
+ if (stmt.condition.static_type.data_type != bool_type.data_type) {
+ stmt.error = true;
+ Report.error (stmt.condition.source_reference, "Condition must be boolean");
+ return;
+ }
+ }
+
+ public override void visit_while_statement (WhileStatement! stmt) {
+ if (stmt.condition.static_type.data_type != bool_type.data_type) {
+ stmt.error = true;
+ Report.error (stmt.condition.source_reference, "Condition must be boolean");
+ return;
+ }
+ }
+
+ public override void visit_for_statement (ForStatement! stmt) {
+ if (stmt.condition.static_type.data_type != bool_type.data_type) {
+ stmt.error = true;
+ Report.error (stmt.condition.source_reference, "Condition must be boolean");
+ return;
+ }
+ }
+
+ public override void visit_begin_foreach_statement (ForeachStatement! stmt) {
+ if (stmt.type_reference.data_type != null) {
+ current_source_file.add_symbol_dependency (stmt.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE);
+ }
+
+ stmt.variable_declarator = new VariableDeclarator (stmt.variable_name);
+ stmt.variable_declarator.type_reference = stmt.type_reference;
+
+ stmt.variable_declarator.symbol = new Symbol (stmt.variable_declarator);
+ stmt.body.symbol.add (stmt.variable_name, stmt.variable_declarator.symbol);
+ }
+
+ public override void visit_end_foreach_statement (ForeachStatement! stmt) {
+ var collection_type = stmt.collection.static_type.data_type;
+ if (!(collection_type is Array || collection_type == glist_type || collection_type == gslist_type)) {
+ stmt.error = true;
+ Report.error (stmt.source_reference, "Collection not iterable");
+ return;
+ }
+ }
+
+ public override void visit_end_return_statement (ReturnStatement! stmt) {
+ if (current_return_type == null) {
+ stmt.error = true;
+ Report.error (stmt.source_reference, "Return not allowed in this context");
+ return;
+ }
+
+ if (stmt.return_expression == null && current_return_type.data_type != null) {
+ stmt.error = true;
+ Report.error (stmt.source_reference, "Return without value in non-void function");
+ return;
+ }
+
+ if (stmt.return_expression != null &&
+ current_return_type.data_type == null &&
+ current_return_type.type_parameter == null) {
+ Report.error (stmt.source_reference, "Return with value in void function");
+ return;
+ }
+
+ if (stmt.return_expression != null &&
+ !is_type_compatible (stmt.return_expression.static_type, current_return_type)) {
+ Report.error (stmt.source_reference, "Return: Cannot convert from `%s' to `%s'".printf (stmt.return_expression.static_type.to_string (), current_return_type.to_string ()));
+ return;
+ }
+
+ if (stmt.return_expression != null &&
+ stmt.return_expression.static_type.transfers_ownership &&
+ !current_return_type.transfers_ownership) {
+ stmt.error = true;
+ Report.error (stmt.source_reference, "Return value transfers ownership but method return type hasn't been declared to transfer ownership");
+ return;
+ }
+
+ if (stmt.return_expression != null &&
+ stmt.return_expression.symbol_reference != null &&
+ stmt.return_expression.symbol_reference.node is VariableDeclarator &&
+ stmt.return_expression.static_type.takes_ownership &&
+ !current_return_type.transfers_ownership) {
+ Report.warning (stmt.source_reference, "Local variable with strong reference used as return value and method return type hasn't been declared to transfer ownership");
+ }
+ }
+
+ /**
+ * Visit operation called for lock statements.
+ *
+ * @param stmt a lock statement
+ */
+ public override void visit_lock_statement (LockStatement! stmt) {
+ /* resource must be a member access and denote a Lockable */
+ if (!(stmt.resource is MemberAccess && stmt.resource.symbol_reference.node is Lockable)) {
+ stmt.error = true;
+ stmt.resource.error = true;
+ Report.error (stmt.resource.source_reference, "Expression is either not a member access or does not denote a lockable member");
+ return;
+ }
+
+ /* parent symbol must be the current class */
+ if (stmt.resource.symbol_reference.parent_symbol.node != current_class) {
+ stmt.error = true;
+ stmt.resource.error = true;
+ Report.error (stmt.resource.source_reference, "Only members of the current class are lockable");
+ }
+
+ ((Lockable)stmt.resource.symbol_reference.node).set_lock_used (true);
+ }
+
+ public override void visit_begin_array_creation_expression (ArrayCreationExpression! expr) {
+ if (expr.initializer_list != null) {
+ expr.initializer_list.expected_type = expr.element_type.copy ();
+ expr.initializer_list.expected_type.data_type = expr.initializer_list.expected_type.data_type.get_array (expr.rank);
+ // FIXME: add element type to type_argument
+ }
+ }
+
+ /**
+ * Visit operations called for array creation expresions.
+ *
+ * @param expr an array creation expression
+ */
+ public override void visit_end_array_creation_expression (ArrayCreationExpression! expr) {
+ int i;
+ List<weak Expression> size = expr.get_sizes ();
+
+ /* check for errors in the size list */
+ if (size != null) {
+ foreach (Expression e in size) {
+ if (e.static_type == null) {
+ /* return on previous error */
+ return;
+ } else if (!(e.static_type.data_type is Struct) || !((Struct) e.static_type.data_type).is_integer_type ()) {
+ expr.error = true;
+ Report.error (e.source_reference, "Expression of integer type expected");
+ }
+ }
+
+ if (expr.error) {
+ return;
+ }
+ }
+
+ /* check for wrong elements inside the initializer */
+ if (expr.initializer_list != null && expr.initializer_list.static_type == null) {
+ return;
+ }
+
+ /* try to construct the type of the array */
+ if (expr.element_type == null) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Cannot determine the element type of the created array");
+ return;
+ }
+
+ expr.static_type = expr.element_type.copy ();
+ if (expr.element_type.data_type != null) {
+ expr.static_type.data_type = expr.element_type.data_type.get_array (expr.rank);
+ } else {
+ expr.static_type.data_type = expr.element_type.type_parameter.get_array (expr.rank);
+ }
+ expr.static_type.transfers_ownership = true;
+ expr.static_type.takes_ownership = true;
+
+ expr.static_type.add_type_argument (expr.element_type);
+ }
+
+ public override void visit_boolean_literal (BooleanLiteral! expr) {
+ expr.static_type = bool_type;
+ }
+
+ public override void visit_character_literal (CharacterLiteral! expr) {
+ expr.static_type = new TypeReference ();
+ expr.static_type.data_type = (DataType) root_symbol.lookup ("char").node;
+ }
+
+ public override void visit_integer_literal (IntegerLiteral! expr) {
+ expr.static_type = new TypeReference ();
+ expr.static_type.data_type = (DataType) root_symbol.lookup (expr.get_type_name ()).node;
+ }
+
+ public override void visit_real_literal (RealLiteral! expr) {
+ expr.static_type = new TypeReference ();
+ expr.static_type.data_type = (DataType) root_symbol.lookup (expr.get_type_name ()).node;
+ }
+
+ public override void visit_string_literal (StringLiteral! expr) {
+ expr.static_type = string_type.copy ();
+ expr.static_type.non_null = true;
+ }
+
+ public override void visit_null_literal (NullLiteral! expr) {
+ /* empty TypeReference represents null */
+
+ expr.static_type = new TypeReference ();
+ }
+
+ public override void visit_literal_expression (LiteralExpression! expr) {
+ expr.static_type = expr.literal.static_type;
+ }
+
+ ref TypeReference get_static_type_for_node (CodeNode! node) {
+ if (node is Field) {
+ var f = (Field) node;
+ return f.type_reference;
+ } else if (node is Constant) {
+ var c = (Constant) node;
+ return c.type_reference;
+ } else if (node is Property) {
+ var prop = (Property) node;
+ var type = prop.type_reference.copy ();
+ type.takes_ownership = false;
+ return type;
+ } else if (node is FormalParameter) {
+ var p = (FormalParameter) node;
+ return p.type_reference;
+ } else if (node is TypeReference) {
+ return (TypeReference) node;
+ } else if (node is VariableDeclarator) {
+ var decl = (VariableDeclarator) node;
+ return decl.type_reference;
+ } else if (node is EnumValue || node is FlagsValue) {
+ var type = new TypeReference ();
+ type.data_type = (DataType) node.symbol.parent_symbol.node;
+ return type;
+ }
+ return null;
+ }
+
+ public static Symbol symbol_lookup_inherited (Symbol! sym, string! name) {
+ var result = sym.lookup (name);
+ if (result != null) {
+ return result;
+ }
+
+ if (sym.node is Class) {
+ var cl = (Class) sym.node;
+ foreach (TypeReference base_type in cl.get_base_types ()) {
+ result = symbol_lookup_inherited (base_type.data_type.symbol, name);
+ if (result != null) {
+ return result;
+ }
+ }
+ } else if (sym.node is Struct) {
+ var st = (Struct) sym.node;
+ foreach (TypeReference base_type in st.get_base_types ()) {
+ result = symbol_lookup_inherited (base_type.data_type.symbol, name);
+ if (result != null) {
+ return result;
+ }
+ }
+ } else if (sym.node is Interface) {
+ var iface = (Interface) sym.node;
+ foreach (TypeReference prerequisite in iface.get_prerequisites ()) {
+ result = symbol_lookup_inherited (prerequisite.data_type.symbol, name);
+ if (result != null) {
+ return result;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public override void visit_parenthesized_expression (ParenthesizedExpression! expr) {
+ expr.static_type = expr.inner.static_type.copy ();
+ // don't call g_object_ref_sink on inner and outer expression
+ expr.static_type.floating_reference = false;
+ }
+
+ private DataType find_parent_type (Symbol sym) {
+ while (sym != null) {
+ if (sym.node is DataType) {
+ return (DataType) sym.node;
+ }
+ sym = sym.parent_symbol;
+ }
+ return null;
+ }
+
+ public override void visit_member_access (MemberAccess! expr) {
+ Symbol base_symbol = null;
+
+ if (expr.inner == null) {
+ base_symbol = current_symbol;
+
+ var sym = current_symbol;
+ while (sym != null && expr.symbol_reference == null) {
+ expr.symbol_reference = symbol_lookup_inherited (sym, expr.member_name);
+ sym = sym.parent_symbol;
+ }
+
+ if (expr.symbol_reference == null) {
+ foreach (NamespaceReference ns in current_using_directives) {
+ var local_sym = ns.namespace_symbol.lookup (expr.member_name);
+ if (local_sym != null) {
+ if (expr.symbol_reference != null) {
+ expr.error = true;
+ Report.error (expr.source_reference, "`%s' is an ambiguous reference between `%s' and `%s'".printf (expr.member_name, expr.symbol_reference.get_full_name (), local_sym.get_full_name ()));
+ return;
+ }
+ expr.symbol_reference = local_sym;
+ }
+ }
+ }
+ } else {
+ if (expr.inner.error) {
+ /* if there was an error in the inner expression, skip this check */
+ expr.error = true;
+ return;
+ }
+
+ if (expr.inner is MemberAccess || expr.inner is BaseAccess) {
+ base_symbol = expr.inner.symbol_reference;
+ if (base_symbol.node is Namespace ||
+ base_symbol.node is DataType) {
+ expr.symbol_reference = base_symbol.lookup (expr.member_name);
+ }
+ }
+
+ if (expr.symbol_reference == null && expr.inner.static_type != null) {
+ base_symbol = expr.inner.static_type.data_type.symbol;
+ expr.symbol_reference = symbol_lookup_inherited (base_symbol, expr.member_name);
+ }
+ }
+
+ if (expr.symbol_reference == null) {
+ expr.error = true;
+ Report.error (expr.source_reference, "The name `%s' does not exist in the context of `%s'".printf (expr.member_name, base_symbol.get_full_name ()));
+ return;
+ }
+
+ var member = expr.symbol_reference.node;
+ MemberAccessibility access = MemberAccessibility.PUBLIC;
+ if (member is Field) {
+ access = ((Field) member).access;
+ } else if (member is Method) {
+ access = ((Method) member).access;
+ }
+
+ if (access == MemberAccessibility.PRIVATE) {
+ var target_type = (DataType) member.symbol.parent_symbol.node;
+ var this_type = find_parent_type (current_symbol);
+
+ if (target_type != this_type) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Access to private member `%s' denied".printf (member.symbol.get_full_name ()));
+ return;
+ }
+ }
+
+ current_source_file.add_symbol_dependency (expr.symbol_reference, SourceFileDependencyType.SOURCE);
+
+ expr.static_type = get_static_type_for_node (expr.symbol_reference.node);
+ }
+
+ private bool is_type_compatible (TypeReference! expression_type, TypeReference! expected_type) {
+ /* only null is compatible to null */
+ if (expected_type.data_type == null && expected_type.type_parameter == null) {
+ return (expression_type.data_type == null && expected_type.type_parameter == null);
+ }
+
+ if (expression_type.data_type == null) {
+ /* null can be cast to any reference or array type or pointer type */
+ if (expected_type.type_parameter != null ||
+ expected_type.data_type.is_reference_type () ||
+ expected_type.reference_to_value_type ||
+ expected_type.data_type is Pointer ||
+ expected_type.data_type is Array ||
+ expected_type.data_type is Callback ||
+ expected_type.data_type == pointer_type) {
+ return true;
+ }
+
+ /* null is not compatible with any other type (i.e. value types) */
+ return false;
+ }
+
+ /* temporarily ignore type parameters */
+ if (expected_type.type_parameter != null) {
+ return true;
+ }
+
+ if (expression_type.data_type is Array != expected_type.data_type is Array) {
+ return false;
+ }
+
+ if (expression_type.data_type is Enum && expected_type.data_type == int_type.data_type) {
+ return true;
+ }
+
+ if (expression_type.data_type == expected_type.data_type) {
+ return true;
+ }
+
+ if (expression_type.data_type is Struct && expected_type.data_type is Struct) {
+ var expr_struct = (Struct) expression_type.data_type;
+ var expect_struct = (Struct) expected_type.data_type;
+
+ /* integer types may be implicitly cast to floating point types */
+ if (expr_struct.is_integer_type () && expect_struct.is_floating_type ()) {
+ return true;
+ }
+
+ if ((expr_struct.is_integer_type () && expect_struct.is_integer_type ()) ||
+ (expr_struct.is_floating_type () && expect_struct.is_floating_type ())) {
+ if (expr_struct.get_rank () <= expect_struct.get_rank ()) {
+ return true;
+ }
+ }
+ }
+
+ return expression_type.data_type.is_subtype_of (expected_type.data_type);
+ }
+
+ public override void visit_begin_invocation_expression (InvocationExpression! expr) {
+ if (expr.call.error) {
+ /* if method resolving didn't succeed, skip this check */
+ expr.error = true;
+ return;
+ }
+
+ var msym = expr.call.symbol_reference;
+
+ if (msym == null) {
+ /* if no symbol found, skip this check */
+ expr.error = true;
+ return;
+ }
+
+ List<weak FormalParameter> params;
+
+ if (msym.node is Invokable) {
+ var m = (Invokable) msym.node;
+ if (m.is_invokable ()) {
+ params = m.get_parameters ();
+ } else {
+ expr.error = true;
+ Report.error (expr.source_reference, "invocation not supported in this context");
+ return;
+ }
+ } else {
+ expr.error = true;
+ Report.error (expr.source_reference, "invocation not supported in this context");
+ return;
+ }
+
+ var args = expr.get_argument_list ();
+ weak List<weak Expression> arg_it = args;
+ foreach (FormalParameter param in params) {
+ if (param.ellipsis) {
+ break;
+ }
+
+ if (arg_it != null) {
+ var arg = (Expression) arg_it.data;
+
+ /* store expected type for callback parameters */
+ arg.expected_type = param.type_reference;
+
+ arg_it = arg_it.next;
+ }
+ }
+ }
+
+ private bool check_arguments (Expression! expr, Symbol! msym, List<FormalParameter> params, List<Expression> args) {
+ weak List<weak Expression> prev_arg_it = null;
+ weak List<weak Expression> arg_it = args;
+
+ bool diag = (msym.node.get_attribute ("Diagnostics") != null);
+
+ bool ellipsis = false;
+ int i = 0;
+ foreach (FormalParameter param in params) {
+ if (param.ellipsis) {
+ ellipsis = true;
+ break;
+ }
+
+ /* header file necessary if we need to cast argument */
+ if (param.type_reference.data_type != null) {
+ current_source_file.add_symbol_dependency (param.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE);
+ }
+
+ if (arg_it == null) {
+ if (param.default_expression == null) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Too few arguments, method `%s' does not take %d arguments".printf (msym.get_full_name (), args.length ()));
+ return false;
+ }
+ } else {
+ var arg = (Expression) arg_it.data;
+ if (arg.static_type != null && !is_type_compatible (arg.static_type, param.type_reference)) {
+ /* if there was an error in the argument,
+ * i.e. arg.static_type == null, skip type check */
+ expr.error = true;
+ Report.error (expr.source_reference, "Argument %d: Cannot convert from `%s' to `%s'".printf (i + 1, arg.static_type.to_string (), param.type_reference.to_string ()));
+ return false;
+ }
+
+ prev_arg_it = arg_it;
+ arg_it = arg_it.next;
+
+ i++;
+ }
+ }
+
+ if (!ellipsis && arg_it != null) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Too many arguments, method `%s' does not take %d arguments".printf (msym.get_full_name (), args.length ()));
+ return false;
+ }
+
+ if (diag && prev_arg_it != null) {
+ var format_arg = (Expression) prev_arg_it.data;
+ if (format_arg is LiteralExpression) {
+ var format_lit = (StringLiteral) ((LiteralExpression) format_arg).literal;
+ format_lit.value = "\"%s:%d: %s".printf (expr.source_reference.file.filename, expr.source_reference.first_line, format_lit.value.offset (1));
+ }
+ }
+
+ return true;
+ }
+
+ public override void visit_end_invocation_expression (InvocationExpression! expr) {
+ if (expr.error) {
+ return;
+ }
+
+ var msym = expr.call.symbol_reference;
+
+ ref TypeReference ret_type;
+ List<weak FormalParameter> params;
+
+ if (msym.node is Invokable) {
+ var m = (Invokable) msym.node;
+ ret_type = m.get_return_type ();
+ params = m.get_parameters ();
+
+ if (ret_type.data_type == null && ret_type.type_parameter == null) {
+ // void return type
+ if (!(expr.parent_node is ExpressionStatement)) {
+ expr.error = true;
+ Report.error (expr.source_reference, "invocation of void method not allowed as expression");
+ return;
+ }
+ }
+
+ // resolve generic return values
+ if (ret_type.type_parameter != null) {
+ if (!(expr.call is MemberAccess)) {
+ Report.error (((CodeNode) m).source_reference, "internal error: unsupported generic return value");
+ expr.error = true;
+ return;
+ }
+ var ma = (MemberAccess) expr.call;
+ if (ma.inner == null) {
+ // TODO resolve generic return values within the type hierarchy if possible
+ Report.error (expr.source_reference, "internal error: resolving generic return values within type hierarchy not supported yet");
+ expr.error = true;
+ return;
+ } else {
+ ref TypeReference instance_type = ma.inner.static_type;
+ // trace type arguments back to the datatype where the method has been declared
+ while (instance_type.data_type != msym.parent_symbol.node) {
+ List<weak TypeReference> base_types = null;
+ if (instance_type.data_type is Class) {
+ var cl = (Class) instance_type.data_type;
+ base_types = cl.get_base_types ();
+ } else if (instance_type.data_type is Interface) {
+ var iface = (Interface) instance_type.data_type;
+ base_types = iface.get_prerequisites ();
+ } else {
+ Report.error (expr.source_reference, "internal error: unsupported generic type");
+ expr.error = true;
+ return;
+ }
+ foreach (TypeReference base_type in base_types) {
+ if (symbol_lookup_inherited (base_type.data_type.symbol, msym.name) != null) {
+ // construct a new type reference for the base type with correctly linked type arguments
+ var instance_base_type = new TypeReference ();
+ instance_base_type.data_type = base_type.data_type;
+ foreach (TypeReference type_arg in base_type.get_type_arguments ()) {
+ if (type_arg.type_parameter != null) {
+ // link to type argument of derived type
+ int param_index = instance_type.data_type.get_type_parameter_index (type_arg.type_parameter.name);
+ if (param_index == -1) {
+ Report.error (expr.source_reference, "internal error: unknown type parameter %s".printf (type_arg.type_parameter.name));
+ expr.error = true;
+ return;
+ }
+ type_arg = instance_type.get_type_arguments ().nth_data (param_index);
+ }
+ instance_base_type.add_type_argument (type_arg);
+ }
+ instance_type = instance_base_type;
+ }
+ }
+ }
+ if (instance_type.data_type != msym.parent_symbol.node) {
+ Report.error (expr.source_reference, "internal error: generic type parameter tracing not supported yet");
+ expr.error = true;
+ return;
+ }
+ int param_index = instance_type.data_type.get_type_parameter_index (ret_type.type_parameter.name);
+ if (param_index == -1) {
+ Report.error (expr.source_reference, "internal error: unknown type parameter %s".printf (ret_type.type_parameter.name));
+ expr.error = true;
+ return;
+ }
+ ret_type = (TypeReference) instance_type.get_type_arguments ().nth_data (param_index);
+ if (ret_type == null) {
+ Report.error (expr.source_reference, "internal error: no actual argument found for type parameter %s".printf (ret_type.type_parameter.name));
+ expr.error = true;
+ return;
+ }
+ }
+ }
+ }
+
+ expr.static_type = ret_type;
+
+ check_arguments (expr, msym, params, expr.get_argument_list ());
+ }
+
+ public override void visit_element_access (ElementAccess! expr) {
+ if (expr.container.static_type == null) {
+ /* don't proceed if a child expression failed */
+ expr.error = true;
+ return;
+ }
+
+ /* assign a static_type when possible */
+ if (expr.container.static_type.data_type is Array) {
+ var args = expr.container.static_type.get_type_arguments ();
+
+ if (args.length () != 1) {
+ expr.error = true;
+ Report.error (expr.source_reference, "internal error: array reference with %d type arguments, expected 1".printf (args.length ()));
+ return;
+ }
+
+ expr.static_type = (TypeReference) args.data;
+ } else {
+ expr.error = true;
+ Report.error (expr.source_reference, "The expression `%s' does not denote an Array".printf (expr.container.static_type.to_string ()));
+ }
+
+ /* check if the index is of type integer */
+ foreach (Expression e in expr.get_indices ()) {
+ /* don't proceed if a child expression failed */
+ if (e.static_type == null) {
+ return;
+ }
+
+ /* check if the index is of type integer */
+ if (!(e.static_type.data_type is Struct) || !((Struct) e.static_type.data_type).is_integer_type ()) {
+ expr.error = true;
+ Report.error (e.source_reference, "Expression of integer type expected");
+ }
+ }
+ }
+
+ public override void visit_base_access (BaseAccess! expr) {
+ if (current_class == null) {
+ if (current_struct == null) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Base access invalid outside of class and struct");
+ return;
+ } else if (current_struct.get_base_types ().length () != 1) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Base access invalid without base type %d".printf (current_struct.get_base_types ().length ()));
+ return;
+ }
+ expr.static_type = current_struct.get_base_types ().first ().data;
+ } else {
+ expr.static_type = new TypeReference ();
+ expr.static_type.data_type = current_class.base_class;
+ }
+
+ expr.symbol_reference = expr.static_type.data_type.symbol;
+ }
+
+ public override void visit_postfix_expression (PostfixExpression! expr) {
+ expr.static_type = expr.inner.static_type;
+ }
+
+ public override void visit_end_object_creation_expression (ObjectCreationExpression! expr) {
+ DataType type = null;
+
+ if (expr.type_reference == null) {
+ if (expr.member_name == null) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Incomplete object creation expression");
+ return;
+ }
+
+ if (expr.member_name.symbol_reference == null) {
+ expr.error = true;
+ return;
+ }
+
+ var constructor_node = expr.member_name.symbol_reference.node;
+ var type_node = expr.member_name.symbol_reference.node;
+
+ var type_args = expr.member_name.get_type_arguments ();
+
+ if (constructor_node is Method) {
+ type_node = constructor_node.symbol.parent_symbol.node;
+
+ var constructor = (Method) constructor_node;
+ if (!(constructor_node is CreationMethod)) {
+ expr.error = true;
+ Report.error (expr.source_reference, "`%s' is not a creation method".printf (constructor.symbol.get_full_name ()));
+ return;
+ }
+
+ expr.symbol_reference = constructor.symbol;
+
+ type_args = ((MemberAccess) expr.member_name.inner).get_type_arguments ();
+ }
+
+ if (type_node is Class || type_node is Struct) {
+ type = (DataType) type_node;
+ } else {
+ expr.error = true;
+ Report.error (expr.source_reference, "`%s' is not a class or struct".printf (type.symbol.get_full_name ()));
+ return;
+ }
+
+ expr.type_reference = new TypeReference ();
+ expr.type_reference.data_type = type;
+ foreach (TypeReference type_arg in type_args) {
+ expr.type_reference.add_type_argument (type_arg);
+ }
+ } else {
+ type = expr.type_reference.data_type;
+ }
+
+ if (!type.is_reference_type ()) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Can't create instance of value type `%s'".printf (expr.type_reference.to_string ()));
+ return;
+ }
+
+ current_source_file.add_symbol_dependency (type.symbol, SourceFileDependencyType.SOURCE);
+
+ expr.static_type = expr.type_reference.copy ();
+ expr.static_type.transfers_ownership = true;
+
+ if (type is Class) {
+ var cl = (Class) type;
+
+ if (cl.is_abstract) {
+ expr.static_type = null;
+ expr.error = true;
+ Report.error (expr.source_reference, "Can't create instance of abstract class `%s'".printf (cl.symbol.get_full_name ()));
+ return;
+ }
+
+ if (expr.symbol_reference == null && cl.default_construction_method != null) {
+ expr.symbol_reference = cl.default_construction_method.symbol;
+ }
+
+ while (cl != null) {
+ if (cl == initially_unowned_type) {
+ expr.static_type.floating_reference = true;
+ break;
+ }
+
+ cl = cl.base_class;
+ }
+ } else if (type is Struct) {
+ var st = (Struct) type;
+
+ if (expr.symbol_reference == null && st.default_construction_method != null) {
+ expr.symbol_reference = st.default_construction_method.symbol;
+ }
+ }
+
+ if (expr.symbol_reference == null && expr.get_argument_list ().length () != 0) {
+ expr.static_type = null;
+ expr.error = true;
+ Report.error (expr.source_reference, "No arguments allowed when constructing type `%s'".printf (type.symbol.get_full_name ()));
+ return;
+ }
+
+ if (expr.symbol_reference != null) {
+ var m = (Method) expr.symbol_reference.node;
+ check_arguments (expr, m.symbol, m.get_parameters (), expr.get_argument_list ());
+ }
+ }
+
+ public override void visit_typeof_expression (TypeofExpression! expr) {
+ expr.static_type = type_type;
+ }
+
+ private bool is_numeric_type (TypeReference! type) {
+ if (!(type.data_type is Struct)) {
+ return false;
+ }
+
+ var st = (Struct) type.data_type;
+ return st.is_integer_type () || st.is_floating_type ();
+ }
+
+ private bool is_integer_type (TypeReference! type) {
+ if (!(type.data_type is Struct)) {
+ return false;
+ }
+
+ var st = (Struct) type.data_type;
+ return st.is_integer_type ();
+ }
+
+ public override void visit_unary_expression (UnaryExpression! expr) {
+ if (expr.inner.error) {
+ /* if there was an error in the inner expression, skip type check */
+ expr.error = true;
+ return;
+ }
+
+ if (expr.operator == UnaryOperator.PLUS || expr.operator == UnaryOperator.MINUS) {
+ // integer or floating point type
+ if (!is_numeric_type (expr.inner.static_type)) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Operator not supported for `%s'".printf (expr.inner.static_type.to_string ()));
+ return;
+ }
+
+ expr.static_type = expr.inner.static_type;
+ } else if (expr.operator == UnaryOperator.LOGICAL_NEGATION) {
+ // boolean type
+ if (expr.inner.static_type.data_type != bool_type.data_type) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Operator not supported for `%s'".printf (expr.inner.static_type.to_string ()));
+ return;
+ }
+
+ expr.static_type = expr.inner.static_type;
+ } else if (expr.operator == UnaryOperator.BITWISE_COMPLEMENT) {
+ // integer type
+ if (!is_integer_type (expr.inner.static_type)) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Operator not supported for `%s'".printf (expr.inner.static_type.to_string ()));
+ return;
+ }
+
+ expr.static_type = expr.inner.static_type;
+ } else if (expr.operator == UnaryOperator.INCREMENT ||
+ expr.operator == UnaryOperator.DECREMENT) {
+ // integer type
+ if (!is_integer_type (expr.inner.static_type)) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Operator not supported for `%s'".printf (expr.inner.static_type.to_string ()));
+ return;
+ }
+
+ var ma = find_member_access (expr.inner);
+ if (ma == null) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Prefix operators not supported for this expression");
+ return;
+ }
+
+ var old_value = new MemberAccess (ma.inner, ma.member_name);
+ var bin = new BinaryExpression (expr.operator == UnaryOperator.INCREMENT ? BinaryOperator.PLUS : BinaryOperator.MINUS, old_value, new LiteralExpression (new IntegerLiteral ("1")));
+
+ var assignment = new Assignment (ma, bin);
+ expr.parent_node.replace (expr, assignment);
+ assignment.accept (this);
+ return;
+ } else if (expr.operator == UnaryOperator.REF) {
+ // value type
+
+ expr.static_type = expr.inner.static_type;
+ } else if (expr.operator == UnaryOperator.OUT) {
+ // reference type
+
+ expr.static_type = expr.inner.static_type;
+ } else {
+ expr.error = true;
+ Report.error (expr.source_reference, "internal error: unsupported unary operator");
+ return;
+ }
+ }
+
+ private MemberAccess find_member_access (Expression! expr) {
+ if (expr is ParenthesizedExpression) {
+ var pe = (ParenthesizedExpression) expr;
+ return find_member_access (pe.inner);
+ }
+
+ if (expr is MemberAccess) {
+ return (MemberAccess) expr;
+ }
+
+ return null;
+ }
+
+ public override void visit_cast_expression (CastExpression! expr) {
+ if (expr.type_reference.data_type == null && expr.type_reference.type_parameter == null) {
+ /* if type resolving didn't succeed, skip this check */
+ return;
+ }
+
+ // FIXME: check whether cast is allowed
+
+ if (expr.type_reference.data_type != null) {
+ current_source_file.add_symbol_dependency (expr.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE);
+ }
+
+ expr.static_type = expr.type_reference;
+ }
+
+ public override void visit_pointer_indirection (PointerIndirection! expr) {
+ if (expr.inner.error) {
+ return;
+ }
+ if (expr.inner.static_type == null) {
+ expr.error = true;
+ Report.error (expr.source_reference, "internal error: unknown type of inner expression");
+ return;
+ }
+ if (!(expr.inner.static_type.data_type is Pointer)) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Pointer indirection not supported for this expression");
+ return;
+ }
+
+ var pointer = (Pointer) expr.inner.static_type.data_type;
+
+ expr.static_type = new TypeReference ();
+ expr.static_type.data_type = pointer.referent_type;
+ expr.static_type.takes_ownership = expr.inner.static_type.takes_ownership;
+ }
+
+ public override void visit_addressof_expression (AddressofExpression! expr) {
+ if (expr.inner.error) {
+ return;
+ }
+ if (expr.inner.static_type == null) {
+ expr.error = true;
+ Report.error (expr.source_reference, "internal error: unknown type of inner expression");
+ return;
+ }
+ if (expr.inner.static_type.data_type == null) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Address-of operator not supported for this expression");
+ return;
+ }
+
+ expr.static_type = new TypeReference ();
+ expr.static_type.data_type = expr.inner.static_type.data_type.get_pointer ();
+ expr.static_type.takes_ownership = expr.inner.static_type.takes_ownership;
+ }
+
+ public override void visit_reference_transfer_expression (ReferenceTransferExpression! expr) {
+ if (expr.inner.error) {
+ /* if there was an error in the inner expression, skip type check */
+ expr.error = true;
+ return;
+ }
+
+ if (!(expr.inner is MemberAccess || expr.inner is ElementAccess)) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Reference transfer not supported for this expression");
+ return;
+ }
+
+ if (!expr.inner.static_type.takes_ownership) {
+ expr.error = true;
+ Report.error (expr.source_reference, "No reference to be transferred");
+ return;
+ }
+
+ expr.static_type = expr.inner.static_type.copy ();
+ expr.static_type.transfers_ownership = true;
+ expr.static_type.takes_ownership = false;
+ }
+
+ private ref TypeReference get_arithmetic_result_type (TypeReference! left_type, TypeReference! right_type) {
+ if (!(left_type.data_type is Struct) || !(right_type.data_type is Struct)) {
+ // at least one operand not struct
+ return null;
+ }
+
+ var left = (Struct) left_type.data_type;
+ var right = (Struct) right_type.data_type;
+
+ if ((!left.is_floating_type () && !left.is_integer_type ()) ||
+ (!right.is_floating_type () && !right.is_integer_type ())) {
+ // at least one operand not numeric
+ return null;
+ }
+
+ if (left.is_floating_type () == right.is_floating_type ()) {
+ // both operands integer or floating type
+ if (left.get_rank () >= right.get_rank ()) {
+ return left_type;
+ } else {
+ return right_type;
+ }
+ } else {
+ // one integer and one floating type operand
+ if (left.is_floating_type ()) {
+ return left_type;
+ } else {
+ return right_type;
+ }
+ }
+ }
+
+ public override void visit_binary_expression (BinaryExpression! expr) {
+ if (expr.left.error || expr.right.error) {
+ /* if there were any errors in inner expressions, skip type check */
+ expr.error = true;
+ return;
+ }
+
+ if (expr.left.static_type.data_type == string_type.data_type
+ && expr.operator == BinaryOperator.PLUS) {
+ if (expr.right.static_type.data_type != string_type.data_type) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Operands must be strings");
+ return;
+ }
+
+ /* string concatenation: convert to a.concat (b) */
+
+ var concat_call = new InvocationExpression (new MemberAccess (expr.left, "concat"));
+ concat_call.add_argument (expr.right);
+
+ expr.parent_node.replace (expr, concat_call);
+
+ concat_call.accept (this);
+ } else if (expr.operator == BinaryOperator.PLUS
+ || expr.operator == BinaryOperator.MINUS
+ || expr.operator == BinaryOperator.MUL
+ || expr.operator == BinaryOperator.DIV) {
+ expr.static_type = get_arithmetic_result_type (expr.left.static_type, expr.right.static_type);
+
+ if (expr.static_type == null) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Arithmetic operation not supported for types `%s' and `%s'".printf (expr.left.static_type.to_string (), expr.right.static_type.to_string ()));
+ return;
+ }
+ } else if (expr.operator == BinaryOperator.MOD
+ || expr.operator == BinaryOperator.SHIFT_LEFT
+ || expr.operator == BinaryOperator.SHIFT_RIGHT
+ || expr.operator == BinaryOperator.BITWISE_XOR) {
+ expr.static_type = get_arithmetic_result_type (expr.left.static_type, expr.right.static_type);
+
+ if (expr.static_type == null) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Arithmetic operation not supported for types `%s' and `%s'".printf (expr.left.static_type.to_string (), expr.right.static_type.to_string ()));
+ return;
+ }
+ } else if (expr.operator == BinaryOperator.LESS_THAN
+ || expr.operator == BinaryOperator.GREATER_THAN
+ || expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL
+ || expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
+ if (expr.left.static_type.data_type == string_type.data_type
+ && expr.right.static_type.data_type == string_type.data_type) {
+ /* string comparison: convert to a.collate (b) OP 0 */
+
+ var cmp_call = new InvocationExpression (new MemberAccess (expr.left, "collate"));
+ cmp_call.add_argument (expr.right);
+ expr.left = cmp_call;
+
+ expr.right = new LiteralExpression (new IntegerLiteral ("0"));
+
+ expr.left.accept (this);
+ } else {
+ var resulting_type = get_arithmetic_result_type (expr.left.static_type, expr.right.static_type);
+
+ if (resulting_type == null) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Relational operation not supported for types `%s' and `%s'".printf (expr.left.static_type.to_string (), expr.right.static_type.to_string ()));
+ return;
+ }
+ }
+
+ expr.static_type = bool_type;
+ } else if (expr.operator == BinaryOperator.EQUALITY
+ || expr.operator == BinaryOperator.INEQUALITY) {
+ /* relational operation */
+
+ if (!is_type_compatible (expr.right.static_type, expr.left.static_type)
+ && !is_type_compatible (expr.left.static_type, expr.right.static_type)) {
+ Report.error (expr.source_reference, "Equality operation: `%s' and `%s' are incompatible, comparison would always evaluate to false".printf (expr.right.static_type.to_string (), expr.left.static_type.to_string ()));
+ expr.error = true;
+ return;
+ }
+
+ if (expr.left.static_type.data_type == string_type.data_type
+ && expr.right.static_type.data_type == string_type.data_type) {
+ /* string comparison: convert to a.collate (b) OP 0 */
+
+ var cmp_call = new InvocationExpression (new MemberAccess (expr.left, "collate"));
+ cmp_call.add_argument (expr.right);
+ expr.left = cmp_call;
+
+ expr.right = new LiteralExpression (new IntegerLiteral ("0"));
+
+ expr.left.accept (this);
+ }
+
+ expr.static_type = bool_type;
+ } else if (expr.operator == BinaryOperator.BITWISE_AND
+ || expr.operator == BinaryOperator.BITWISE_OR) {
+ // integer type or flags type
+
+ expr.static_type = expr.left.static_type;
+ } else if (expr.operator == BinaryOperator.AND
+ || expr.operator == BinaryOperator.OR) {
+ if (expr.left.static_type.data_type != bool_type.data_type || expr.right.static_type.data_type != bool_type.data_type) {
+ expr.error = true;
+ Report.error (expr.source_reference, "Operands must be boolean");
+ }
+
+ expr.static_type = bool_type;
+ } else {
+ assert_not_reached ();
+ }
+ }
+
+ public override void visit_type_check (TypeCheck! expr) {
+ if (expr.type_reference.data_type == null) {
+ /* if type resolving didn't succeed, skip this check */
+ expr.error = true;
+ return;
+ }
+
+ current_source_file.add_symbol_dependency (expr.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE);
+
+ expr.static_type = bool_type;
+ }
+
+ private TypeReference compute_common_base_type (List<TypeReference> types) {
+ bool null_found = false;
+ bool class_or_iface_found = false;
+ bool type_param_found = false;
+ bool ref_struct_found = false;
+ bool val_struct_found = false;
+ bool enum_found = false;
+ bool callback_found = false;
+ TypeReference base_type = null;
+ TypeReference last_type = null;
+ foreach (TypeReference type in types) {
+ last_type = type;
+ if (type.error) {
+ base_type = new TypeReference ();
+ base_type.error = true;
+ return base_type;
+ }
+ if (type.data_type == null && type.type_parameter == null) {
+ if (!null_found) {
+ null_found = true;
+ if (val_struct_found || enum_found) {
+ base_type.error = true;
+ break;
+ }
+ }
+ } else if (type.data_type is Class || type.data_type is Interface) {
+ if (!class_or_iface_found) {
+ class_or_iface_found = true;
+ if (type_param_found || ref_struct_found || val_struct_found || enum_found || callback_found) {
+ base_type.error = true;
+ break;
+ }
+ }
+ } else if (type.type_parameter != null) {
+ if (!type_param_found) {
+ type_param_found = true;
+ if (class_or_iface_found || ref_struct_found || val_struct_found || enum_found || callback_found) {
+ base_type.error = true;
+ break;
+ }
+ }
+ } else if (type.data_type is Struct) {
+ var st = (Struct) type.data_type;
+ if (st.is_reference_type ()) {
+ if (!ref_struct_found) {
+ ref_struct_found = true;
+ if (class_or_iface_found || type_param_found || val_struct_found || enum_found || callback_found) {
+ base_type.error = true;
+ break;
+ }
+ }
+ } else {
+ if (!val_struct_found) {
+ val_struct_found = true;
+ if (class_or_iface_found || type_param_found || ref_struct_found || enum_found || callback_found) {
+ base_type.error = true;
+ break;
+ }
+ }
+ }
+ } else if (type.data_type is Enum) {
+ if (!enum_found) {
+ enum_found = true;
+ if (class_or_iface_found || type_param_found || ref_struct_found || val_struct_found) {
+ base_type.error = true;
+ break;
+ }
+ }
+ } else if (type.data_type is Callback) {
+ if (!callback_found) {
+ callback_found = true;
+ if (class_or_iface_found || type_param_found || ref_struct_found || val_struct_found || enum_found) {
+ base_type.error = true;
+ break;
+ }
+ }
+ } else {
+ base_type = new TypeReference ();
+ base_type.error = true;
+ Report.error (type.source_reference, "internal error: unsupported type `%s'".printf (type.to_string ()));
+ return base_type;
+ }
+ if (base_type == null) {
+ base_type = new TypeReference ();
+ base_type.data_type = type.data_type;
+ base_type.type_parameter = type.type_parameter;
+ base_type.non_null = type.non_null;
+ base_type.is_null = type.is_null;
+ base_type.transfers_ownership = type.transfers_ownership;
+ } else {
+ if (base_type.data_type != type.data_type) {
+ if (is_type_compatible (type, base_type)) {
+ } else if (is_type_compatible (base_type, type)) {
+ base_type.data_type = type.data_type;
+ } else {
+ base_type.error = true;
+ break;
+ }
+ }
+ base_type.non_null = base_type.non_null && type.non_null;
+ base_type.is_null = base_type.is_null && type.is_null;
+ // if one subexpression transfers ownership, all subexpressions must transfer ownership
+ // FIXME add ref calls to subexpressions that don't transfer ownership
+ base_type.transfers_ownership = base_type.transfers_ownership || type.transfers_ownership;
+ }
+ }
+ if (base_type != null && base_type.error) {
+ Report.error (last_type.source_reference, "`%s' is incompatible with `%s'".printf (last_type.to_string (), base_type.to_string ()));
+ }
+ return base_type;
+ }
+
+ public override void visit_conditional_expression (ConditionalExpression! expr) {
+ if (expr.condition.static_type.data_type != bool_type.data_type) {
+ expr.error = true;
+ Report.error (expr.condition.source_reference, "Condition must be boolean");
+ return;
+ }
+
+ /* FIXME: support memory management */
+ List<TypeReference> types;
+ types.append (expr.true_expression.static_type);
+ types.append (expr.false_expression.static_type);
+ expr.static_type = compute_common_base_type (types);
+ }
+
+ private ref string get_lambda_name () {
+ var result = "__lambda%d".printf (next_lambda_id);
+
+ next_lambda_id++;
+
+ return result;
+ }
+
+ private Method find_current_method () {
+ var sym = current_symbol;
+ while (sym != null) {
+ if (sym.node is Method) {
+ return (Method) sym.node;
+ }
+ sym = sym.parent_symbol;
+ }
+ return null;
+ }
+
+ private bool is_in_constructor () {
+ var sym = current_symbol;
+ while (sym != null) {
+ if (sym.node is Constructor) {
+ return true;
+ }
+ sym = sym.parent_symbol;
+ }
+ return false;
+ }
+
+ public override void visit_begin_lambda_expression (LambdaExpression! l) {
+ if (l.expected_type == null || !(l.expected_type.data_type is Callback)) {
+ l.error = true;
+ Report.error (l.source_reference, "lambda expression not allowed in this context");
+ return;
+ }
+
+ bool in_instance_method = false;
+ var current_method = find_current_method ();
+ if (current_method != null) {
+ in_instance_method = current_method.instance;
+ } else {
+ in_instance_method = is_in_constructor ();
+ }
+
+ var cb = (Callback) l.expected_type.data_type;
+ l.method = new Method (get_lambda_name (), cb.return_type);
+ l.method.instance = cb.instance && in_instance_method;
+ l.method.symbol = new Symbol (l.method);
+ l.method.symbol.parent_symbol = current_symbol;
+
+ var lambda_params = l.get_parameters ();
+ weak List<weak FormalParameter> lambda_param_it = lambda_params;
+ foreach (FormalParameter cb_param in cb.get_parameters ()) {
+ if (lambda_param_it == null) {
+ /* lambda expressions are allowed to have less parameters */
+ break;
+ }
+
+ var lambda_param = (string) lambda_param_it.data;
+
+ var param = new FormalParameter (lambda_param, cb_param.type_reference);
+ param.symbol = new Symbol (param);
+ l.method.symbol.add (param.name, param.symbol);
+
+ l.method.add_parameter (param);
+
+ lambda_param_it = lambda_param_it.next;
+ }
+
+ if (lambda_param_it != null) {
+ /* lambda expressions may not expect more parameters */
+ l.error = true;
+ Report.error (l.source_reference, "lambda expression: too many parameters");
+ return;
+ }
+
+ if (l.expression_body != null) {
+ var block = new Block ();
+ block.symbol = new Symbol (block);
+ block.symbol.parent_symbol = l.method.symbol;
+
+ if (l.method.return_type.data_type != null) {
+ block.add_statement (new ReturnStatement (l.expression_body));
+ } else {
+ block.add_statement (new ExpressionStatement (l.expression_body));
+ }
+
+ l.method.body = block;
+ } else {
+ l.method.body = l.statement_body;
+ l.method.body.symbol.parent_symbol = l.method.symbol;
+ }
+
+ /* lambda expressions should be usable like MemberAccess of a method */
+ l.symbol_reference = l.method.symbol;
+ }
+
+ public override void visit_begin_assignment (Assignment! a) {
+ if (a.left is MemberAccess) {
+ var ma = (MemberAccess) a.left;
+
+ if (ma.error || ma.symbol_reference == null) {
+ a.error = true;
+ /* if no symbol found, skip this check */
+ return;
+ }
+
+ if (ma.symbol_reference.node is Signal) {
+ var sig = (Signal) ma.symbol_reference.node;
+
+ a.right.expected_type = new TypeReference ();
+ a.right.expected_type.data_type = sig.get_callback ();
+ }
+ } else if (a.left is ElementAccess) {
+ // do nothing
+ } else if (a.left is PointerIndirection) {
+ // do nothing
+ } else {
+ a.error = true;
+ Report.error (a.source_reference, "unsupported lvalue in assignment");
+ }
+ }
+
+ public override void visit_end_assignment (Assignment! a) {
+ if (a.error || a.left.error || a.right.error) {
+ a.error = true;
+ return;
+ }
+
+ if (a.operator != AssignmentOperator.SIMPLE && a.left is MemberAccess) {
+ // transform into simple assignment
+ // FIXME: only do this if the backend doesn't support
+ // the assignment natively
+
+ var ma = (MemberAccess) a.left;
+
+ if (!(ma.symbol_reference.node is Signal)) {
+ var old_value = new MemberAccess (ma.inner, ma.member_name);
+
+ var bin = new BinaryExpression (BinaryOperator.PLUS, old_value, new ParenthesizedExpression (a.right, a.right.source_reference));
+
+ if (a.operator == AssignmentOperator.BITWISE_OR) {
+ bin.operator = BinaryOperator.BITWISE_OR;
+ } else if (a.operator == AssignmentOperator.BITWISE_AND) {
+ bin.operator = BinaryOperator.BITWISE_AND;
+ } else if (a.operator == AssignmentOperator.BITWISE_XOR) {
+ bin.operator = BinaryOperator.BITWISE_XOR;
+ } else if (a.operator == AssignmentOperator.ADD) {
+ bin.operator = BinaryOperator.PLUS;
+ } else if (a.operator == AssignmentOperator.SUB) {
+ bin.operator = BinaryOperator.MINUS;
+ } else if (a.operator == AssignmentOperator.MUL) {
+ bin.operator = BinaryOperator.MUL;
+ } else if (a.operator == AssignmentOperator.DIV) {
+ bin.operator = BinaryOperator.DIV;
+ } else if (a.operator == AssignmentOperator.PERCENT) {
+ bin.operator = BinaryOperator.MOD;
+ } else if (a.operator == AssignmentOperator.SHIFT_LEFT) {
+ bin.operator = BinaryOperator.SHIFT_LEFT;
+ } else if (a.operator == AssignmentOperator.SHIFT_RIGHT) {
+ bin.operator = BinaryOperator.SHIFT_RIGHT;
+ }
+
+ a.right = bin;
+ a.right.accept (this);
+
+ a.operator = AssignmentOperator.SIMPLE;
+ }
+ }
+
+ if (a.left is MemberAccess) {
+ var ma = (MemberAccess) a.left;
+
+ if (ma.symbol_reference.node is Signal) {
+ var sig = (Signal) ma.symbol_reference.node;
+
+ if (a.right.symbol_reference == null) {
+ a.error = true;
+ Report.error (a.right.source_reference, "unsupported expression for signal handler");
+ return;
+ }
+
+ var m = (Method) a.right.symbol_reference.node;
+
+ if (m.instance && m.access != MemberAccessibility.PRIVATE) {
+ /* TODO: generate wrapper function */
+
+ ma.error = true;
+ Report.error (a.right.source_reference, "public instance methods not yet supported as signal handlers");
+ return;
+ }
+
+ if (m.instance) {
+ /* instance signal handlers must have the self
+ * parameter at the end
+ * do not use G_CONNECT_SWAPPED as this would
+ * rearrange the parameters for instance
+ * methods and non-instance methods
+ */
+ m.instance_last = true;
+ }
+ } else if (ma.symbol_reference.node is Property) {
+ var prop = (Property) ma.symbol_reference.node;
+
+ if (prop.set_accessor == null) {
+ ma.error = true;
+ Report.error (ma.source_reference, "Property `%s' is read-only".printf (prop.symbol.get_full_name ()));
+ return;
+ }
+ } else if (ma.symbol_reference.node is VariableDeclarator && a.right.static_type == null) {
+ var decl = (VariableDeclarator) ma.symbol_reference.node;
+
+ var right_ma = (MemberAccess) a.right;
+ if (right_ma.symbol_reference.node is Method &&
+ decl.type_reference.data_type is Callback) {
+ var m = (Method) right_ma.symbol_reference.node;
+ var cb = (Callback) decl.type_reference.data_type;
+
+ /* check whether method matches callback type */
+ if (!cb.matches_method (m)) {
+ decl.error = true;
+ Report.error (a.source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.symbol.get_full_name (), cb.symbol.get_full_name ()));
+ return;
+ }
+
+ a.right.static_type = decl.type_reference;
+ } else {
+ a.error = true;
+ Report.error (a.source_reference, "Assignment: Invalid callback assignment attempt");
+ return;
+ }
+ } else if (ma.symbol_reference.node is Field && a.right.static_type == null) {
+ var f = (Field) ma.symbol_reference.node;
+
+ var right_ma = (MemberAccess) a.right;
+ if (right_ma.symbol_reference.node is Method &&
+ f.type_reference.data_type is Callback) {
+ var m = (Method) right_ma.symbol_reference.node;
+ var cb = (Callback) f.type_reference.data_type;
+
+ /* check whether method matches callback type */
+ if (!cb.matches_method (m)) {
+ f.error = true;
+ Report.error (a.source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.symbol.get_full_name (), cb.symbol.get_full_name ()));
+ return;
+ }
+
+ a.right.static_type = f.type_reference;
+ } else {
+ a.error = true;
+ Report.error (a.source_reference, "Assignment: Invalid callback assignment attempt");
+ return;
+ }
+ } else if (a.left.static_type != null && a.right.static_type != null) {
+ if (!is_type_compatible (a.right.static_type, a.left.static_type)) {
+ /* if there was an error on either side,
+ * i.e. a.{left|right}.static_type == null, skip type check */
+ a.error = true;
+ Report.error (a.source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (a.right.static_type.to_string (), a.left.static_type.to_string ()));
+ return;
+ }
+
+ if (memory_management) {
+ if (a.right.static_type.transfers_ownership) {
+ /* rhs transfers ownership of the expression */
+ if (!a.left.static_type.takes_ownership) {
+ /* lhs doesn't own the value */
+ a.error = true;
+ Report.error (a.source_reference, "Invalid assignment from owned expression to unowned variable");
+ }
+ } else if (a.left.static_type.takes_ownership) {
+ /* lhs wants to own the value
+ * rhs doesn't transfer the ownership
+ * code generator needs to add reference
+ * increment calls */
+ }
+ }
+ }
+ } else if (a.left is ElementAccess) {
+ var ea = (ElementAccess) a.left;
+
+ if (!is_type_compatible (a.right.static_type, a.left.static_type)) {
+ /* if there was an error on either side,
+ * i.e. a.{left|right}.static_type == null, skip type check */
+ a.error = true;
+ Report.error (a.source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (a.right.static_type.to_string (), a.left.static_type.to_string ()));
+ return;
+ }
+
+ if (memory_management) {
+ if (a.right.static_type.transfers_ownership) {
+ /* rhs transfers ownership of the expression */
+
+ var args = ea.container.static_type.get_type_arguments ();
+ if (args.length () != 1) {
+ a.error = true;
+ Report.error (ea.source_reference, "internal error: array reference without type arguments");
+ return;
+ }
+ var element_type = (TypeReference) args.data;
+
+ if (!element_type.takes_ownership) {
+ /* lhs doesn't own the value */
+ a.error = true;
+ Report.error (a.source_reference, "Invalid assignment from owned expression to unowned variable");
+ return;
+ }
+ } else if (a.left.static_type.takes_ownership) {
+ /* lhs wants to own the value
+ * rhs doesn't transfer the ownership
+ * code generator needs to add reference
+ * increment calls */
+ }
+ }
+ } else {
+ return;
+ }
+
+ a.static_type = a.left.static_type;
+ }
+}
diff --git a/vala/valasignal.vala b/vala/valasignal.vala
new file mode 100644
index 000000000..5e10a2c97
--- /dev/null
+++ b/vala/valasignal.vala
@@ -0,0 +1,189 @@
+/* valasignal.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;
+
+/**
+ * Represents an object signal. Signals enable objects to provide notifications.
+ */
+public class Vala.Signal : Member, Invokable, Lockable {
+ /**
+ * The symbol name of this signal.
+ */
+ public string! name { get; set construct; }
+
+ /**
+ * The return type of handlers of this signal.
+ */
+ public TypeReference! return_type { get; set construct; }
+
+ /**
+ * Specifies the accessibility of the signal. Currently only public
+ * accessibility is supported for signals.
+ */
+ public MemberAccessibility access { get; set; }
+
+ /**
+ * Specifies whether this signal has an emitter wrapper function.
+ */
+ public bool has_emitter { get; set; }
+
+ private List<FormalParameter> parameters;
+ private Callback generated_callback;
+
+ private string cname;
+
+ private bool lock_used = false;
+
+ /**
+ * Creates a new signal.
+ *
+ * @param name signal name
+ * @param return_type signal return type
+ * @param source reference to source code
+ * @return newly created signal
+ */
+ public Signal (string! _name, TypeReference! _return_type, SourceReference source) {
+ name = _name;
+ return_type = _return_type;
+ source_reference = source;
+ }
+
+ /**
+ * Appends parameter to signal handler.
+ *
+ * @param param a formal parameter
+ */
+ public void add_parameter (FormalParameter! param) {
+ parameters.append (param);
+ }
+
+ public ref List<weak FormalParameter> get_parameters () {
+ return parameters.copy ();
+ }
+
+ public TypeReference get_return_type () {
+ return return_type;
+ }
+
+ public bool is_invokable () {
+ return true;
+ }
+
+ /**
+ * Returns generated callback to be used for signal handlers.
+ *
+ * @return callback
+ */
+ public Callback! get_callback () {
+ if (generated_callback == null) {
+ generated_callback = new Callback (null, return_type);
+ generated_callback.instance = true;
+
+ var sender_type = new TypeReference ();
+ sender_type.data_type = (DataType) symbol.parent_symbol.node;
+ var sender_param = new FormalParameter ("sender", sender_type);
+ generated_callback.add_parameter (sender_param);
+
+ foreach (FormalParameter! param in parameters) {
+ generated_callback.add_parameter (param);
+ }
+ }
+
+ return generated_callback;
+ }
+
+ /**
+ * Returns the name of this signal as it is used in C code.
+ *
+ * @return the name to be used in C code
+ */
+ public string! get_cname () {
+ if (cname == null) {
+ cname = name;
+ }
+ return cname;
+ }
+
+ public void set_cname (string cname) {
+ this.cname = cname;
+ }
+
+ /**
+ * Returns the string literal of this signal to be used in C code.
+ *
+ * @return string literal to be used in C code
+ */
+ public ref CCodeConstant! get_canonical_cconstant () {
+ var str = new String ("\"");
+
+ string i = name;
+
+ while (i.len () > 0) {
+ unichar c = i.get_char ();
+ if (c == '_') {
+ str.append_c ('-');
+ } else {
+ str.append_unichar (c);
+ }
+
+ i = i.next_char ();
+ }
+
+ str.append_c ('"');
+
+ return new CCodeConstant (str.str);
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_member (this);
+
+ visitor.visit_begin_signal (this);
+
+ return_type.accept (visitor);
+
+ foreach (FormalParameter param in parameters) {
+ param.accept (visitor);
+ }
+
+ visitor.visit_end_signal (this);
+ }
+
+ /**
+ * Process all associated attributes.
+ */
+ public void process_attributes () {
+ foreach (Attribute a in attributes) {
+ if (a.name == "HasEmitter") {
+ has_emitter = true;
+ }
+ }
+ }
+
+ public bool get_lock_used () {
+ return lock_used;
+ }
+
+ public void set_lock_used (bool used) {
+ lock_used = used;
+ }
+}
diff --git a/vala/valasourcefile.vala b/vala/valasourcefile.vala
new file mode 100644
index 000000000..11972d536
--- /dev/null
+++ b/vala/valasourcefile.vala
@@ -0,0 +1,355 @@
+/* valasourcefile.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;
+
+/**
+ * Represents a Vala source or VAPI package file.
+ */
+public class Vala.SourceFile {
+ /**
+ * The name of this source file.
+ */
+ public string! filename { get; set construct; }
+
+ /**
+ * The header comment of this source file.
+ */
+ public string comment { get; set; }
+
+ /**
+ * Specifies whether this file is a VAPI package file.
+ */
+ public bool pkg { get; set; }
+
+ /**
+ * Specifies the dependency cycle this source file is member of. If this
+ * source file is in a cycle, all type definitions of that cycle will
+ * only be written to the C header file of the cycle head.
+ */
+ public SourceFileCycle cycle { get; set; }
+
+ /**
+ * Specifies whether this source file is the head of the cycle, if it is
+ * in a cycle at all.
+ */
+ public bool is_cycle_head { get; set; }
+
+ /**
+ * Mark used for cycle detection.
+ *
+ * 0: not yet visited
+ * 1: currently visiting
+ * 2: already visited
+ */
+ public int mark { get; set; }
+
+ /**
+ * The context this source file belongs to.
+ */
+ public weak CodeContext context { get; set; }
+
+ private List<NamespaceReference> using_directives;
+
+ private Namespace global_namespace;
+ private List<Namespace> namespaces;
+
+ private string cheader_filename = null;
+ private string csource_filename = null;
+ private string cinclude_filename = null;
+
+ private List<string> header_external_includes;
+ private List<string> header_internal_includes;
+ private List<string> source_external_includes;
+ private List<string> source_internal_includes;
+
+ private List<weak SourceFile> header_internal_full_dependencies;
+ private List<weak SourceFile> header_internal_dependencies;
+
+ /**
+ * Creates a new source file.
+ *
+ * @param filename source file name
+ * @param pkg true if this is a VAPI package file
+ * @return newly created source file
+ */
+ public SourceFile (CodeContext! _context, string! _filename, bool _pkg = false) {
+ context = _context;
+ filename = _filename;
+ pkg = _pkg;
+ }
+
+ construct {
+ global_namespace = new Namespace (null, new SourceReference (this));
+ }
+
+ /**
+ * Adds a new using directive with the specified namespace.
+ *
+ * @param ns reference to namespace
+ */
+ public void add_using_directive (NamespaceReference! ns) {
+ using_directives.append (ns);
+ }
+
+ /**
+ * Returns a copy of the list of using directives.
+ *
+ * @return using directive list
+ */
+ public ref List<weak NamespaceReference> get_using_directives () {
+ return using_directives.copy ();
+ }
+
+ /**
+ * Adds the specified namespace to this source file.
+ *
+ * @param ns a namespace
+ */
+ public void add_namespace (Namespace! ns) {
+ namespaces.append (ns);
+ }
+
+ /**
+ * Returns the implicitly declared root namespace of this source file.
+ *
+ * @return root namespace
+ */
+ public Namespace! get_global_namespace () {
+ return global_namespace;
+ }
+
+ /**
+ * Returns a copy of the list of namespaces.
+ *
+ * @return namespace list
+ */
+ public ref List<weak Namespace> get_namespaces () {
+ return namespaces.copy ();
+ }
+
+ /**
+ * Visits this source file and all children with the specified
+ * CodeVisitor.
+ *
+ * @param visitor the visitor to be called while traversing
+ */
+ public void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_source_file (this);
+
+ foreach (NamespaceReference ns_ref in using_directives) {
+ ns_ref.accept (visitor);
+ }
+
+ global_namespace.accept (visitor);
+
+ foreach (Namespace ns in namespaces) {
+ ns.accept (visitor);
+ }
+
+ visitor.visit_end_source_file (this);
+ }
+
+ /**
+ * Returns the filename to use when generating C header files.
+ *
+ * @return generated C header filename
+ */
+ public string! get_cheader_filename () {
+ if (cheader_filename == null) {
+ var basename = filename.ndup ((uint) (filename.len () - ".vala".len ()));
+ cheader_filename = "%s.h".printf (basename);
+ }
+ return cheader_filename;
+ }
+
+ /**
+ * Returns the filename to use when generating C source files.
+ *
+ * @return generated C source filename
+ */
+ public string! get_csource_filename () {
+ if (csource_filename == null) {
+ var basename = filename.ndup ((uint) (filename.len () - ".vala".len ()));
+ csource_filename = "%s.c".printf (basename);
+ }
+ return csource_filename;
+ }
+
+ /**
+ * Returns the filename to use when including the generated C header
+ * file.
+ *
+ * @return C header filename to include
+ */
+ public string! get_cinclude_filename () {
+ if (cinclude_filename == null) {
+ var basename = filename.ndup ((uint) (filename.len () - ".vala".len ()));
+ if (context.library != null) {
+ cinclude_filename = "%s/%s.h".printf (context.library, basename);
+ } else {
+ cinclude_filename = "%s.h".printf (basename);
+ }
+ }
+ return cinclude_filename;
+ }
+
+ /**
+ * Adds the specified symbol to the list of symbols code in this source
+ * file depends on.
+ *
+ * @param sym a symbol
+ * @param dep_type type of dependency
+ */
+ public void add_symbol_dependency (Symbol! sym, SourceFileDependencyType dep_type) {
+ DataType t;
+
+ if (sym.node is DataType) {
+ t = (DataType) sym.node;
+ } else if (sym.node is Method || sym.node is Field) {
+ if (sym.parent_symbol.node is DataType) {
+ t = (DataType) sym.parent_symbol.node;
+ } else {
+ return;
+ }
+ } else if (sym.node is Property) {
+ t = (DataType) sym.parent_symbol.node;
+ } else if (sym.node is Constant) {
+ if (sym.parent_symbol.node is DataType) {
+ t = (DataType) sym.parent_symbol.node;
+ } else if (sym.parent_symbol.node is Namespace) {
+ var ns = (Namespace) sym.parent_symbol.node;
+ source_internal_includes.concat (ns.get_cheader_filenames ());
+ return;
+ } else {
+ return;
+ }
+ } else if (sym.node is FormalParameter) {
+ var fp = (FormalParameter) sym.node;
+ t = fp.type_reference.data_type;
+ if (t == null) {
+ /* generic type parameter */
+ return;
+ }
+ } else {
+ return;
+ }
+
+ if (dep_type == SourceFileDependencyType.SOURCE) {
+ if (t.source_reference.file.pkg) {
+ source_external_includes.concat (t.get_cheader_filenames ());
+ } else {
+ source_internal_includes.concat (t.get_cheader_filenames ());
+ }
+ return;
+ }
+
+ if (t.source_reference.file.pkg) {
+ /* external package */
+ header_external_includes.concat (t.get_cheader_filenames ());
+ return;
+ }
+
+ if (dep_type == SourceFileDependencyType.HEADER_FULL || !t.is_reference_type ()) {
+ header_internal_includes.concat (t.get_cheader_filenames ());
+ header_internal_full_dependencies.append (t.source_reference.file);
+ }
+
+ header_internal_dependencies.append (t.source_reference.file);
+ }
+
+ /**
+ * Returns the list of external includes the generated C header file
+ * requires.
+ *
+ * @return external include list for C header file
+ */
+ public weak List<string> get_header_external_includes () {
+ return header_external_includes;
+ }
+
+ /**
+ * Adds the specified filename to the list of package-internal includes
+ * the generated C header file requires.
+ *
+ * @param include internal include for C header file
+ */
+ public void add_header_internal_include (string! include) {
+ header_internal_includes.append (include);
+ }
+
+ /**
+ * Returns the list of package-internal includes the generated C header
+ * file requires.
+ *
+ * @return internal include list for C header file
+ */
+ public weak List<string> get_header_internal_includes () {
+ return header_internal_includes;
+ }
+
+ /**
+ * Returns the list of external includes the generated C source file
+ * requires.
+ *
+ * @return include list for C source file
+ */
+ public weak List<string> get_source_external_includes () {
+ return source_external_includes;
+ }
+
+ /**
+ * Returns the list of package-internal includes the generated C source
+ * file requires.
+ *
+ * @return include list for C source file
+ */
+ public weak List<string> get_source_internal_includes () {
+ return source_internal_includes;
+ }
+
+ /**
+ * Returns the list of source files the generated C header file requires
+ * definitely.
+ *
+ * @return definite source file dependencies
+ */
+ public weak List<SourceFile> get_header_internal_full_dependencies () {
+ return header_internal_full_dependencies;
+ }
+
+ /**
+ * Returns the list of source files the generated C header file loosely
+ * depends on.
+ *
+ * @return loose source file dependencies
+ */
+ public weak List<SourceFile> get_header_internal_dependencies () {
+ return header_internal_dependencies;
+ }
+}
+
+public enum Vala.SourceFileDependencyType {
+ HEADER_FULL,
+ HEADER_SHALLOW,
+ SOURCE
+}
diff --git a/vala/valasourcefilecycle.vala b/vala/valasourcefilecycle.vala
new file mode 100644
index 000000000..e77f6cd4e
--- /dev/null
+++ b/vala/valasourcefilecycle.vala
@@ -0,0 +1,38 @@
+/* valasourcefilecycle.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;
+
+/**
+ * Represents a dependency cycle of source files.
+ */
+public class Vala.SourceFileCycle {
+ /**
+ * The members of this source file cycle.
+ */
+ public List<weak SourceFile> files;
+
+ /**
+ * The head of this source file cycle.
+ */
+ public weak SourceFile head;
+}
diff --git a/vala/valasourcereference.vala b/vala/valasourcereference.vala
new file mode 100644
index 000000000..8bc2f2d60
--- /dev/null
+++ b/vala/valasourcereference.vala
@@ -0,0 +1,103 @@
+/* valasourcereference.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>
+ */
+
+/**
+ * Represents a reference to a location in a source file.
+ */
+public class Vala.SourceReference {
+ /**
+ * The source file to be referenced.
+ */
+ public weak SourceFile file { get; set; }
+
+ /**
+ * The first line number of the referenced source code.
+ */
+ public int first_line { get; set; }
+
+ /**
+ * The first column number of the referenced source code.
+ */
+ public int first_column { get; set; }
+
+ /**
+ * The last line number of the referenced source code.
+ */
+ public int last_line { get; set; }
+
+ /**
+ * The last column number of the referenced source code.
+ */
+ public int last_column { get; set; }
+
+ /**
+ * The text describing the referenced source code.
+ */
+ public string comment { get; set; }
+
+ /**
+ * Creates a new source reference.
+ *
+ * @param file a source file
+ * @param first_line first line number
+ * @param first_column first column number
+ * @param last_line last line number
+ * @param last_column last column number
+ * @return newly created source reference
+ */
+ public SourceReference (SourceFile _file, int _first_line = 0, int _first_column = 0, int _last_line = 0, int _last_column = 0) {
+ file = _file;
+ first_line = _first_line;
+ first_column = _first_column;
+ last_line = _last_line;
+ last_column = _last_column;
+ }
+
+ /**
+ * Creates a new commented source reference.
+ *
+ * @param file a source file
+ * @param first_line first line number
+ * @param first_column first column number
+ * @param last_line last line number
+ * @param last_column last column number
+ * @param comment code comment
+ * @return newly created source reference
+ */
+ public SourceReference.with_comment (SourceFile _file, int _first_line, int _first_column, int _last_line, int _last_column, string _comment) {
+ file = _file;
+ first_line = _first_line;
+ first_column = _first_column;
+ last_line = _last_line;
+ last_column = _last_column;
+ comment = _comment;
+ }
+
+ /**
+ * Returns a string representation of this source reference.
+ *
+ * @return human-readable string
+ */
+ public ref string! to_string () {
+ return ("%s:%d.%d-%d.%d".printf (file.filename, first_line, first_column, last_line, last_column));
+ }
+}
diff --git a/vala/valastatement.vala b/vala/valastatement.vala
new file mode 100644
index 000000000..75cc69af5
--- /dev/null
+++ b/vala/valastatement.vala
@@ -0,0 +1,39 @@
+/* valastatement.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * Base class for all statement types.
+ */
+public abstract class Vala.Statement : CodeNode {
+ /**
+ * Returns the number of construction parameters this statement sets in
+ * maximum or -1 if this statement may not be used in the construction
+ * part of a construction method.
+ *
+ * @return number of construction parameters set or -1
+ */
+ public virtual int get_number_of_set_construction_parameters () {
+ return -1;
+ }
+}
diff --git a/vala/valastringliteral.vala b/vala/valastringliteral.vala
new file mode 100644
index 000000000..82485910f
--- /dev/null
+++ b/vala/valastringliteral.vala
@@ -0,0 +1,65 @@
+/* valastringliteral.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;
+
+/**
+ * Represents a string literal in the source code.
+ */
+public class Vala.StringLiteral : Literal {
+ /**
+ * The literal value.
+ */
+ public string value { get; set; }
+
+ /**
+ * Creates a new string literal.
+ *
+ * @param s the literal value
+ * @param source reference to source code
+ * @return newly created string literal
+ */
+ public StringLiteral (string s, SourceReference source) {
+ value = s;
+ source_reference = source;
+ }
+
+ /**
+ * Evaluates the literal string value.
+ *
+ * @return the unescaped string
+ */
+ public ref string eval () {
+ if (value == null) {
+ return null;
+ }
+
+ /* remove quotes */
+ var noquotes = value.offset (1).ndup ((uint) (value.len () - 2));
+ /* unescape string */
+ return noquotes.compress ();
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_string_literal (this);
+ }
+}
diff --git a/vala/valastruct.vala b/vala/valastruct.vala
new file mode 100644
index 000000000..3e57c6b93
--- /dev/null
+++ b/vala/valastruct.vala
@@ -0,0 +1,436 @@
+/* valastruct.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * Represents a struct declaration in the source code.
+ */
+public class Vala.Struct : DataType {
+ private List<TypeParameter> type_parameters;
+ private List<Constant> constants;
+ private List<Field> fields;
+ private List<Method> methods;
+
+ private List<TypeReference> base_types;
+
+ private string cname;
+ private string const_cname;
+ private string dup_function;
+ private string free_function;
+ private string type_id;
+ private string lower_case_cprefix;
+ private string lower_case_csuffix;
+ private bool reference_type;
+ private bool integer_type;
+ private bool floating_type;
+ private int rank;
+ private string marshaller_type_name;
+ private string get_value_function;
+ private string set_value_function;
+ private string default_value = null;
+
+ /**
+ * Specifies the default construction method.
+ */
+ public Method default_construction_method { get; set; }
+
+ /**
+ * Creates a new struct.
+ *
+ * @param name type name
+ * @param source reference to source code
+ * @return newly created struct
+ */
+ public Struct (string! _name, SourceReference source = null) {
+ name = _name;
+ source_reference = source;
+ }
+
+ /**
+ * Appends the specified parameter to the list of type parameters.
+ *
+ * @param p a type parameter
+ */
+ public void add_type_parameter (TypeParameter! p) {
+ type_parameters.append (p);
+ p.type = this;
+ }
+
+ /**
+ * Adds the specified constant as a member to this struct.
+ *
+ * @param c a constant
+ */
+ public void add_constant (Constant! c) {
+ constants.append (c);
+ }
+
+ /**
+ * Adds the specified field as a member to this struct.
+ *
+ * @param f a field
+ */
+ public void add_field (Field! f) {
+ fields.append (f);
+ }
+
+ /**
+ * Returns a copy of the list of fields.
+ *
+ * @return list of fields
+ */
+ public ref List<weak Field> get_fields () {
+ return fields.copy ();
+ }
+
+ /**
+ * Adds the specified method as a member to this struct.
+ *
+ * @param m a method
+ */
+ public void add_method (Method! m) {
+ return_if_fail (m != null);
+
+ methods.append (m);
+ }
+
+ /**
+ * Returns a copy of the list of methods.
+ *
+ * @return list of methods
+ */
+ public ref List<weak Method> get_methods () {
+ return methods.copy ();
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_struct (this);
+
+ foreach (TypeParameter p in type_parameters) {
+ p.accept (visitor);
+ }
+
+ foreach (Field f in fields) {
+ f.accept (visitor);
+ }
+
+ foreach (Constant c in constants) {
+ c.accept (visitor);
+ }
+
+ foreach (Method m in methods) {
+ m.accept (visitor);
+ }
+
+ visitor.visit_end_struct (this);
+ }
+
+ public override string get_cname (bool const_type = false) {
+ if (const_type && const_cname != null) {
+ return const_cname;
+ }
+
+ if (cname == null) {
+ cname = "%s%s".printf (@namespace.get_cprefix (), name);
+ }
+ return cname;
+ }
+
+ private void set_cname (string! cname) {
+ this.cname = cname;
+ }
+
+ private void set_const_cname (string! cname) {
+ this.const_cname = cname;
+ }
+
+ public override ref string get_lower_case_cprefix () {
+ if (lower_case_cprefix == null) {
+ lower_case_cprefix = "%s_".printf (get_lower_case_cname (null));
+ }
+ return lower_case_cprefix;
+ }
+
+ private string get_lower_case_csuffix () {
+ if (lower_case_csuffix == null) {
+ lower_case_csuffix = Namespace.camel_case_to_lower_case (name);
+ }
+ return lower_case_csuffix;
+ }
+
+ private void set_lower_case_csuffix (string! csuffix) {
+ this.lower_case_csuffix = csuffix;
+ }
+
+ public override ref string get_lower_case_cname (string infix) {
+ if (infix == null) {
+ infix = "";
+ }
+ return "%s%s%s".printf (@namespace.get_lower_case_cprefix (), infix, get_lower_case_csuffix ());
+ }
+
+ public override ref string get_upper_case_cname (string infix) {
+ return get_lower_case_cname (infix).up ();
+ }
+
+ public override bool is_reference_type () {
+ return reference_type;
+ }
+
+ /**
+ * Returns whether this is an integer type.
+ *
+ * @return true if this is an integer type, false otherwise
+ */
+ public bool is_integer_type () {
+ return integer_type;
+ }
+
+ /**
+ * Returns whether this is a floating point type.
+ *
+ * @return true if this is a floating point type, false otherwise
+ */
+ public bool is_floating_type () {
+ return floating_type;
+ }
+
+ /**
+ * Returns the rank of this integer or floating point type.
+ *
+ * @return the rank if this is an integer or floating point type
+ */
+ public int get_rank () {
+ return rank;
+ }
+
+ /**
+ * Sets whether this data type has value or reference type semantics.
+ *
+ * @param ref_type true if this data type has reference type semantics
+ */
+ public void set_is_reference_type (bool ref_type) {
+ reference_type = ref_type;
+ }
+
+ private void process_ccode_attribute (Attribute! a) {
+ if (a.has_argument ("cname")) {
+ set_cname (a.get_string ("cname"));
+ }
+ if (a.has_argument ("const_cname")) {
+ set_const_cname (a.get_string ("const_cname"));
+ }
+ if (a.has_argument ("cprefix")) {
+ lower_case_cprefix = a.get_string ("cprefix");
+ }
+ if (a.has_argument ("cheader_filename")) {
+ var val = a.get_string ("cheader_filename");
+ foreach (string filename in val.split (",")) {
+ add_cheader_filename (filename);
+ }
+ }
+ if (a.has_argument ("type_id")) {
+ set_type_id (a.get_string ("type_id"));
+ }
+ if (a.has_argument ("marshaller_type_name")) {
+ set_marshaller_type_name (a.get_string ("marshaller_type_name"));
+ }
+ if (a.has_argument ("get_value_function")) {
+ set_get_value_function (a.get_string ("get_value_function"));
+ }
+ if (a.has_argument ("set_value_function")) {
+ set_set_value_function (a.get_string ("set_value_function"));
+ }
+ if (a.has_argument ("default_value")) {
+ set_default_value (a.get_string ("default_value"));
+ }
+ }
+
+ private void process_ref_type_attribute (Attribute! a) {
+ reference_type = true;
+ if (a.has_argument ("dup_function")) {
+ set_dup_function (a.get_string ("dup_function"));
+ }
+ if (a.has_argument ("free_function")) {
+ set_free_function (a.get_string ("free_function"));
+ }
+ }
+
+ private void process_integer_type_attribute (Attribute! a) {
+ integer_type = true;
+ if (a.has_argument ("rank")) {
+ rank = a.get_integer ("rank");
+ }
+ }
+
+ private void process_floating_type_attribute (Attribute! a) {
+ floating_type = true;
+ if (a.has_argument ("rank")) {
+ rank = a.get_integer ("rank");
+ }
+ }
+
+ /**
+ * Process all associated attributes.
+ */
+ public void process_attributes () {
+ foreach (Attribute a in attributes) {
+ if (a.name == "CCode") {
+ process_ccode_attribute (a);
+ } else if (a.name == "ReferenceType") {
+ process_ref_type_attribute (a);
+ } else if (a.name == "IntegerType") {
+ process_integer_type_attribute (a);
+ } else if (a.name == "FloatingType") {
+ process_floating_type_attribute (a);
+ }
+ }
+ }
+
+ public override bool is_reference_counting () {
+ return false;
+ }
+
+ public override string get_dup_function () {
+ if (dup_function == null) {
+ Report.error (source_reference, "The type `%s` doesn't contain a copy function".printf (symbol.get_full_name ()));
+ }
+ return dup_function;
+ }
+
+ public void set_dup_function (string! name) {
+ this.dup_function = name;
+ }
+
+ public override string get_free_function () {
+ if (free_function == null) {
+ Report.error (source_reference, "The type `%s` doesn't contain a free function".printf (symbol.get_full_name ()));
+ }
+ return free_function;
+ }
+
+ private void set_free_function (string! name) {
+ this.free_function = name;
+ }
+
+ public override string get_type_id () {
+ if (type_id == null) {
+ if (is_reference_type ()) {
+ type_id = "G_TYPE_POINTER";
+ } else {
+ Report.error (source_reference, "The type `%s` doesn't declare a type id".printf (symbol.get_full_name ()));
+ }
+ }
+ return type_id;
+ }
+
+ public void set_type_id (string! name) {
+ this.type_id = name;
+ }
+
+ public override string get_marshaller_type_name () {
+ if (marshaller_type_name == null) {
+ if (is_reference_type ()) {
+ marshaller_type_name = "POINTER";
+ } else {
+ Report.error (source_reference, "The type `%s` doesn't declare a marshaller type name".printf (symbol.get_full_name ()));
+ }
+ }
+ return marshaller_type_name;
+ }
+
+ private void set_marshaller_type_name (string! name) {
+ this.marshaller_type_name = name;
+ }
+
+ public override string get_get_value_function () {
+ if (get_value_function == null) {
+ if (is_reference_type ()) {
+ return "g_value_get_pointer";
+ } else {
+ Report.error (source_reference, "The value type `%s` doesn't declare a GValue get function".printf (symbol.get_full_name ()));
+ }
+ } else {
+ return get_value_function;
+ }
+ }
+
+ public override string get_set_value_function () {
+ if (set_value_function == null) {
+ if (is_reference_type ()) {
+ return "g_value_set_pointer";
+ } else {
+ Report.error (source_reference, "The value type `%s` doesn't declare a GValue set function".printf (symbol.get_full_name ()));
+ }
+ } else {
+ return set_value_function;
+ }
+ }
+
+ private void set_get_value_function (string! function) {
+ get_value_function = function;
+ }
+
+ private void set_set_value_function (string! function) {
+ set_value_function = function;
+ }
+
+ public override string get_default_value () {
+ return default_value;
+ }
+
+ private void set_default_value (string! value) {
+ default_value = value;
+ }
+
+ /**
+ * Adds the specified struct to the list of base types of this struct.
+ *
+ * @param type a class or interface reference
+ */
+ public void add_base_type (TypeReference! type) {
+ base_types.append (type);
+ }
+
+ /**
+ * Returns a copy of the base type list.
+ *
+ * @return list of base types
+ */
+ public ref List<weak TypeReference> get_base_types () {
+ return base_types.copy ();
+ }
+
+ public override int get_type_parameter_index (string! name) {
+ int i = 0;
+
+ foreach (TypeParameter p in type_parameters) {
+ if (p.name == name) {
+ return (i);
+ }
+ i++;
+ }
+
+ return -1;
+ }
+}
diff --git a/vala/valaswitchlabel.vala b/vala/valaswitchlabel.vala
new file mode 100644
index 000000000..6a2e5f9fb
--- /dev/null
+++ b/vala/valaswitchlabel.vala
@@ -0,0 +1,65 @@
+/* valaswitchlabel.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;
+
+/**
+ * Represents a switch label in the source code.
+ */
+public class Vala.SwitchLabel : CodeNode {
+ /**
+ * Specifies the label expression.
+ */
+ public Expression expression { get; set; }
+
+ /**
+ * Creates a new switch case label.
+ *
+ * @param expr label expression
+ * @param source reference to source code
+ * @return newly created switch case label
+ */
+ public SwitchLabel (Expression expr, SourceReference source = null) {
+ expression = expr;
+ source_reference = source;
+ }
+
+ /**
+ * Creates a new switch default label.
+ *
+ * @param source reference to source code
+ * @return newly created switch default label
+ */
+ public SwitchLabel.with_default (SourceReference source = null) {
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ if (expression != null) {
+ expression.accept (visitor);
+
+ visitor.visit_end_full_expression (expression);
+ }
+
+ visitor.visit_switch_label (this);
+ }
+}
diff --git a/vala/valaswitchsection.vala b/vala/valaswitchsection.vala
new file mode 100644
index 000000000..0bb6fa7a1
--- /dev/null
+++ b/vala/valaswitchsection.vala
@@ -0,0 +1,99 @@
+/* valaswitchsection.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;
+
+/**
+ * Represents a switch section in the source code.
+ */
+public class Vala.SwitchSection : CodeNode {
+ private List<SwitchLabel> labels;
+ private List<Statement> statement_list;
+
+ /**
+ * Creates a new switch section.
+ *
+ * @param source reference to source code
+ * @return newly created switch section
+ */
+ public SwitchSection (SourceReference source) {
+ source_reference = source;
+ }
+
+ /**
+ * Appends the specified label to the list of switch labels.
+ *
+ * @param label a switch label
+ */
+ public void add_label (SwitchLabel! label) {
+ labels.append (label);
+ }
+
+ /**
+ * Returns a copy of the list of switch labels.
+ *
+ * @return switch label list
+ */
+ public ref List<weak SwitchLabel> get_labels () {
+ return labels.copy ();
+ }
+
+ public bool has_default_label () {
+ foreach (SwitchLabel label in labels) {
+ if (label.expression == null) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Appends the specified statement to this switch section.
+ *
+ * @param stmt a statement
+ */
+ public void add_statement (Statement! stmt) {
+ statement_list.append (stmt);
+ }
+
+ /**
+ * Returns a copy of the list of statements.
+ *
+ * @return statement list
+ */
+ public ref List<weak Statement> get_statements () {
+ return statement_list.copy ();
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ foreach (SwitchLabel label in labels) {
+ label.accept (visitor);
+ }
+
+ foreach (Statement st in statement_list) {
+ st.accept (visitor);
+ }
+
+ visitor.visit_switch_section (this);
+ }
+}
diff --git a/vala/valaswitchstatement.vala b/vala/valaswitchstatement.vala
new file mode 100644
index 000000000..cf7edc641
--- /dev/null
+++ b/vala/valaswitchstatement.vala
@@ -0,0 +1,92 @@
+/* valaswitchstatement.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;
+
+/**
+ * Represents a switch selection statement in the source code.
+ */
+public class Vala.SwitchStatement : Statement {
+ /**
+ * Specifies the switch expression.
+ */
+ public Expression! expression {
+ get {
+ return _expression;
+ }
+ set construct {
+ _expression = value;
+ _expression.parent_node = this;
+ }
+ }
+
+ private Expression! _expression;
+ private List<SwitchSection> sections;
+
+ /**
+ * Creates a new switch statement.
+ *
+ * @param expr switch expression
+ * @param source reference to source code
+ * @return newly created switch statement
+ */
+ public SwitchStatement (Expression! expr, SourceReference source) {
+ expression = expr;
+ source_reference = source;
+ }
+
+ /**
+ * Appends the specified section to the list of switch sections.
+ *
+ * @param section a switch section
+ */
+ public void add_section (SwitchSection! section) {
+ sections.append (section);
+ }
+
+ /**
+ * Returns a copy of the list of switch sections.
+ *
+ * @return section list
+ */
+ public ref List<weak SwitchSection> get_sections () {
+ return sections.copy ();
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ expression.accept (visitor);
+
+ visitor.visit_end_full_expression (expression);
+
+ foreach (SwitchSection section in sections) {
+ section.accept (visitor);
+ }
+
+ visitor.visit_switch_statement (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (expression == old_node) {
+ expression = (Expression) new_node;
+ }
+ }
+}
diff --git a/vala/valasymbol.vala b/vala/valasymbol.vala
new file mode 100644
index 000000000..d93eff738
--- /dev/null
+++ b/vala/valasymbol.vala
@@ -0,0 +1,119 @@
+/* valasymbol.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;
+
+/**
+ * Represents a node in the symbol tree.
+ */
+public class Vala.Symbol {
+ /**
+ * The code node that created this symbol, if applicable.
+ */
+ public weak CodeNode node { get; set; }
+
+ /**
+ * The parent of this symbol.
+ */
+ public weak Symbol parent_symbol { get; set; }
+
+ /**
+ * The symbol name.
+ */
+ public string name { get; set; }
+
+ /**
+ * Specifies whether this symbol is active.
+ *
+ * Symbols may become inactive when they only apply to a part of a
+ * scope. This is used for local variables not declared at the beginning
+ * of the block to determine which variables need to be freed before
+ * jump statements.
+ */
+ public bool active { get; set; }
+
+ private HashTable<string,Symbol> symbol_table = new HashTable.full (str_hash, str_equal, g_free, g_object_unref);
+
+ /**
+ * Creates a new symbol.
+ *
+ * @param node the corresponding code node
+ * @return newly created symbol
+ */
+ public Symbol (CodeNode _node = null) {
+ node = _node;
+ }
+
+ construct {
+ active = true;
+ }
+
+ /**
+ * Returns the fully expanded name of this symbol for use in
+ * human-readable messages.
+ *
+ * @return full name
+ */
+ public ref string get_full_name () {
+ if (parent_symbol == null) {
+ return name;
+ }
+
+ if (name == null) {
+ return parent_symbol.get_full_name ();
+ }
+
+ if (parent_symbol.get_full_name () == null) {
+ return name;
+ }
+
+ return "%s.%s".printf (parent_symbol.get_full_name (), name);
+ }
+
+ /**
+ * Adds the specified symbol with the specified name to the symbol table
+ * of this symbol.
+ *
+ * @param name name for the specified symbol
+ * @param sym a symbol
+ */
+ public void add (string! name, Symbol! sym) {
+ symbol_table.insert (name, sym);
+ sym.parent_symbol = this;
+ sym.name = name;
+ }
+
+ /**
+ * Returns the symbol stored in the symbol table with the specified
+ * name.
+ *
+ * @param name name of the symbol to be returned
+ * @return found symbol or null
+ */
+ public Symbol lookup (string! name) {
+ Symbol sym = symbol_table.lookup (name);
+ if (sym != null && !sym.active) {
+ sym = null;
+ }
+ return sym;
+ }
+}
diff --git a/vala/valasymbolbuilder.vala b/vala/valasymbolbuilder.vala
new file mode 100644
index 000000000..0bceb41b5
--- /dev/null
+++ b/vala/valasymbolbuilder.vala
@@ -0,0 +1,429 @@
+/* valasymbolbuilder.vala
+ *
+ * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
+ *
+ * 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>
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+using GLib;
+
+/**
+ * Code visitor building the symbol tree.
+ */
+public class Vala.SymbolBuilder : CodeVisitor {
+ Symbol root;
+ Symbol current_type;
+ Symbol current_symbol;
+ SourceFile current_source_file;
+
+ /**
+ * Build the symbol tree for the specified code context.
+ *
+ * @param context a code context
+ */
+ public void build (CodeContext! context) {
+ root = context.get_root ();
+ context.accept (this);
+ }
+
+ public override void visit_begin_source_file (SourceFile! file) {
+ current_source_file = file;
+ }
+
+ public override void visit_begin_namespace (Namespace! ns) {
+ if (ns.name == null) {
+ ns.symbol = root;
+ }
+
+ if (ns.symbol == null) {
+ ns.symbol = root.lookup (ns.name);
+ }
+ if (ns.symbol == null) {
+ ns.symbol = new Symbol (ns);
+ root.add (ns.name, ns.symbol);
+ }
+
+ current_symbol = ns.symbol;
+ }
+
+ public override void visit_end_namespace (Namespace! ns) {
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ private weak Symbol add_symbol (string name, CodeNode! node) {
+ if (name != null) {
+ if (current_symbol.lookup (name) != null) {
+ node.error = true;
+ Report.error (node.source_reference, "`%s' already contains a definition for `%s'".printf (current_symbol.get_full_name (), name));
+ return null;
+ }
+ }
+ node.symbol = new Symbol (node);
+ if (name != null) {
+ current_symbol.add (name, node.symbol);
+ } else {
+ node.symbol.parent_symbol = current_symbol;
+ }
+
+ return node.symbol;
+ }
+
+ public override void visit_begin_class (Class! cl) {
+ var class_symbol = current_symbol.lookup (cl.name);
+ if (class_symbol == null || !(class_symbol.node is Class)) {
+ class_symbol = add_symbol (cl.name, cl);
+ } else {
+ /* merge this class declaration with existing class symbol */
+ var main_class = (Class) class_symbol.node;
+ foreach (TypeReference base_type in cl.get_base_types ()) {
+ main_class.add_base_type (base_type);
+ }
+ foreach (Field f in cl.get_fields ()) {
+ main_class.add_field (f);
+ }
+ foreach (Method m in cl.get_methods ()) {
+ main_class.add_method (m);
+ }
+ foreach (Property prop in cl.get_properties ()) {
+ main_class.add_property (prop, true);
+ }
+ foreach (Signal sig in cl.get_signals ()) {
+ main_class.add_signal (sig);
+ }
+ if (cl.constructor != null) {
+ if (main_class.constructor != null) {
+ cl.error = true;
+ Report.error (cl.constructor.source_reference, "`%s' already contains a constructor".printf (current_symbol.get_full_name ()));
+ return;
+ }
+ main_class.constructor = cl.constructor;
+ }
+ if (cl.destructor != null) {
+ if (main_class.destructor != null) {
+ cl.error = true;
+ Report.error (cl.destructor.source_reference, "`%s' already contains a destructor".printf (current_symbol.get_full_name ()));
+ return;
+ }
+ main_class.destructor = cl.destructor;
+ }
+ }
+
+ current_symbol = class_symbol;
+ }
+
+ public override void visit_end_class (Class! cl) {
+ if (cl.error) {
+ /* skip classes with errors */
+ return;
+ }
+
+ current_symbol = current_symbol.parent_symbol;
+
+ if (cl.symbol == null) {
+ /* remove merged class */
+ cl.@namespace.remove_class (cl);
+ }
+ }
+
+ public override void visit_begin_struct (Struct! st) {
+ if (add_symbol (st.name, st) == null) {
+ return;
+ }
+
+ current_symbol = st.symbol;
+ }
+
+ public override void visit_end_struct (Struct! st) {
+ if (st.error) {
+ /* skip structs with errors */
+ return;
+ }
+
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_begin_interface (Interface! iface) {
+ if (add_symbol (iface.name, iface) == null) {
+ return;
+ }
+
+ current_symbol = iface.symbol;
+ }
+
+ public override void visit_end_interface (Interface! iface) {
+ if (iface.error) {
+ /* skip interfaces with errors */
+ return;
+ }
+
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_begin_enum (Enum! en) {
+ if (add_symbol (en.name, en) == null) {
+ return;
+ }
+
+ current_symbol = en.symbol;
+ }
+
+ public override void visit_end_enum (Enum! en) {
+ if (en.error) {
+ /* skip enums with errors */
+ return;
+ }
+
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_enum_value (EnumValue! ev) {
+ ev.symbol = new Symbol (ev);
+ current_symbol.add (ev.name, ev.symbol);
+ }
+
+ public override void visit_begin_flags (Flags! fl) {
+ if (add_symbol (fl.name, fl) == null) {
+ return;
+ }
+
+ current_symbol = fl.symbol;
+ }
+
+ public override void visit_end_flags (Flags! fl) {
+ if (fl.error) {
+ /* skip flags with errors */
+ return;
+ }
+
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_flags_value (FlagsValue! fv) {
+ fv.symbol = new Symbol (fv);
+ current_symbol.add (fv.name, fv.symbol);
+ }
+
+ public override void visit_begin_callback (Callback! cb) {
+ if (add_symbol (cb.name, cb) == null) {
+ return;
+ }
+
+ 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) {
+ add_symbol (c.name, c);
+ }
+
+ public override void visit_field (Field! f) {
+ add_symbol (f.name, f);
+ }
+
+ public override void visit_begin_method (Method! m) {
+ if (add_symbol (m.name, m) == null) {
+ return;
+ }
+
+ if (m.instance) {
+ if (!(m.symbol.parent_symbol.node is DataType)) {
+ Report.error (m.source_reference, "instance methods not allowed outside of data types");
+
+ m.error = true;
+ return;
+ }
+
+ m.this_parameter = new FormalParameter ("this", new TypeReference ());
+ m.this_parameter.type_reference.data_type = (DataType) m.symbol.parent_symbol.node;
+ m.this_parameter.symbol = new Symbol (m.this_parameter);
+ current_symbol.add (m.this_parameter.name, m.this_parameter.symbol);
+ }
+
+ current_symbol = m.symbol;
+ }
+
+ public override void visit_end_method (Method! m) {
+ if (m.error) {
+ /* skip methods with errors */
+ return;
+ }
+
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_begin_creation_method (CreationMethod! m) {
+ if (add_symbol (m.name, m) == null) {
+ return;
+ }
+
+ var type_node = m.symbol.parent_symbol.node;
+ if (!(type_node is Class || type_node is Struct)) {
+ Report.error (m.source_reference, "construction methods may only be declared within classes and structs");
+
+ m.error = true;
+ return;
+ }
+
+ if (m.name == null) {
+ if (type_node is Class) {
+ ((Class) type_node).default_construction_method = m;
+ } else if (type_node is Struct) {
+ ((Struct) type_node).default_construction_method = m;
+ }
+ }
+
+ current_symbol = m.symbol;
+ }
+
+ public override void visit_end_creation_method (CreationMethod! m) {
+ if (m.error) {
+ /* skip methods with errors */
+ return;
+ }
+
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_formal_parameter (FormalParameter! p) {
+ if (!p.ellipsis) {
+ add_symbol (p.name, p);
+ }
+ }
+
+ public override void visit_begin_property (Property! prop) {
+ if (add_symbol (prop.name, prop) == null) {
+ return;
+ }
+
+ current_symbol = prop.symbol;
+
+ prop.this_parameter = new FormalParameter ("this", new TypeReference ());
+ prop.this_parameter.type_reference.data_type = (DataType) prop.symbol.parent_symbol.node;
+ prop.this_parameter.symbol = new Symbol (prop.this_parameter);
+ current_symbol.add (prop.this_parameter.name, prop.this_parameter.symbol);
+ }
+
+ public override void visit_end_property (Property! prop) {
+ if (prop.error) {
+ /* skip properties with errors */
+ return;
+ }
+
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_begin_property_accessor (PropertyAccessor! acc) {
+ acc.symbol = new Symbol (acc);
+ acc.symbol.parent_symbol = current_symbol;
+ current_symbol = acc.symbol;
+
+ if (current_source_file.pkg) {
+ return;
+ }
+
+ if (acc.writable || acc.construction) {
+ acc.value_parameter = new FormalParameter ("value", ((Property) current_symbol.parent_symbol.node).type_reference);
+ acc.value_parameter.symbol = new Symbol (acc.value_parameter);
+
+ current_symbol.add (acc.value_parameter.name, acc.value_parameter.symbol);
+ }
+
+ if (acc.body == null) {
+ /* no accessor body specified, insert default body */
+
+ var prop = (Property) acc.symbol.parent_symbol.node;
+
+ if (prop.interface_only || prop.is_abstract) {
+ return;
+ }
+
+ var block = new Block ();
+ if (acc.readable) {
+ block.add_statement (new ReturnStatement (new MemberAccess.simple ("_%s".printf (prop.name))));
+ } else {
+ block.add_statement (new ExpressionStatement (new Assignment (new MemberAccess.simple ("_%s".printf (prop.name)), new MemberAccess.simple ("value"))));
+ }
+ acc.body = block;
+ }
+ }
+
+ public override void visit_end_property_accessor (PropertyAccessor! acc) {
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_begin_signal (Signal! sig) {
+ if (add_symbol (sig.name, sig) == null) {
+ return;
+ }
+
+ current_symbol = sig.symbol;
+ }
+
+ public override void visit_end_signal (Signal! sig) {
+ if (sig.error) {
+ /* skip signals with errors */
+ return;
+ }
+
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_begin_constructor (Constructor! c) {
+ c.symbol = new Symbol (c);
+ c.symbol.parent_symbol = current_symbol;
+ current_symbol = c.symbol;
+ }
+
+ public override void visit_end_constructor (Constructor! c) {
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_begin_destructor (Destructor! d) {
+ d.symbol = new Symbol (d);
+ d.symbol.parent_symbol = current_symbol;
+ current_symbol = d.symbol;
+ }
+
+ public override void visit_end_destructor (Destructor! d) {
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_begin_block (Block! b) {
+ b.symbol = new Symbol (b);
+ b.symbol.parent_symbol = current_symbol;
+ current_symbol = b.symbol;
+ }
+
+ public override void visit_end_block (Block! b) {
+ current_symbol = current_symbol.parent_symbol;
+ }
+
+ public override void visit_type_parameter (TypeParameter! p) {
+ add_symbol (p.name, p);
+ }
+}
+
diff --git a/vala/valasymbolresolver.vala b/vala/valasymbolresolver.vala
new file mode 100644
index 000000000..483871bce
--- /dev/null
+++ b/vala/valasymbolresolver.vala
@@ -0,0 +1,249 @@
+/* valasymbolresolver.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * Code visitor resolving symbol names.
+ */
+public class Vala.SymbolResolver : CodeVisitor {
+ Symbol root_symbol;
+ Symbol current_scope;
+ List<weak NamespaceReference> current_using_directives;
+
+ Class object_class;
+
+ /**
+ * Resolve symbol names in the specified code context.
+ *
+ * @param context a code context
+ */
+ public void resolve (CodeContext! context) {
+ root_symbol = context.get_root ();
+ current_scope = root_symbol;
+
+ // TODO: don't require GLib namespace in symbol resolver
+ var glib_ns = root_symbol.lookup ("GLib");
+ if (glib_ns != null) {
+ object_class = (Class) glib_ns.lookup ("Object").node;
+ }
+
+ context.accept (this);
+ }
+
+ public override void visit_begin_source_file (SourceFile! file) {
+ current_using_directives = file.get_using_directives ();
+ }
+
+ public override void visit_end_source_file (SourceFile! file) {
+ current_using_directives = null;
+ }
+
+ public override void visit_begin_namespace (Namespace! ns) {
+ current_scope = ns.symbol;
+ }
+
+ public override void visit_end_namespace (Namespace! ns) {
+ // don't use current_scope.parent_symbol as that would be null
+ // if the current namespace is SourceFile.global_namespace
+ current_scope = root_symbol;
+ }
+
+ public override void visit_begin_class (Class! cl) {
+ current_scope = cl.symbol;
+ }
+
+ public override void visit_end_class (Class! cl) {
+ foreach (TypeReference type in cl.get_base_types ()) {
+ if (type.data_type is Class) {
+ if (cl.base_class != null) {
+ Report.error (type.source_reference, "%s: Classes cannot have multiple base classes (`%s' and `%s')".printf (cl.symbol.get_full_name (), cl.base_class.symbol.get_full_name (), type.data_type.symbol.get_full_name ()));
+ return;
+ }
+ cl.base_class = (Class) type.data_type;
+ }
+ }
+ if (cl.base_class == null && cl != object_class) {
+ var object_type = new TypeReference ();
+ object_type.data_type = object_class;
+ cl.add_base_type (object_type);
+ cl.base_class = object_class;
+ }
+
+ current_scope = current_scope.parent_symbol;
+ }
+
+ public override void visit_begin_struct (Struct! st) {
+ current_scope = st.symbol;
+ }
+
+ public override void visit_end_struct (Struct! st) {
+ current_scope = current_scope.parent_symbol;
+ }
+
+ public override void visit_begin_interface (Interface! iface) {
+ current_scope = iface.symbol;
+ }
+
+ public override void visit_end_interface (Interface! iface) {
+ current_scope = current_scope.parent_symbol;
+ }
+
+ public override void visit_begin_callback (Callback! cb) {
+ current_scope = cb.symbol;
+ }
+
+ public override void visit_end_callback (Callback! cb) {
+ current_scope = current_scope.parent_symbol;
+ }
+
+ public override void visit_formal_parameter (FormalParameter! p) {
+ if (!p.ellipsis && p.type_reference.is_ref) {
+ if ((p.type_reference.data_type != null &&
+ p.type_reference.data_type.is_reference_type ()) ||
+ p.type_reference.type_parameter != null) {
+ p.type_reference.takes_ownership = true;
+ } else {
+ p.type_reference.reference_to_value_type = true;
+ }
+ }
+ }
+
+ public override void visit_namespace_reference (NamespaceReference! ns) {
+ ns.namespace_symbol = current_scope.lookup (ns.name);
+ if (ns.namespace_symbol == null) {
+ ns.error = true;
+ Report.error (ns.source_reference, "The namespace name `%s' could not be found".printf (ns.name));
+ return;
+ }
+ }
+
+ public override void visit_type_reference (TypeReference! type) {
+ if (type.type_name == null || type.type_name == "void") {
+ // reset transfers_ownership
+ type.transfers_ownership = false;
+ return;
+ }
+
+ if (type.namespace_name == null) {
+ Symbol sym = null;
+ Symbol scope = current_scope;
+ while (sym == null && scope != null) {
+ sym = scope.lookup (type.type_name);
+ scope = scope.parent_symbol;
+ if (sym != null && !(sym.node is DataType) && !(sym.node is TypeParameter)) {
+ // ignore non-type symbols
+ sym = null;
+ }
+ }
+ if (sym == null) {
+ foreach (NamespaceReference ns in current_using_directives) {
+ if (ns.error) {
+ continue;
+ }
+
+ var local_sym = ns.namespace_symbol.lookup (type.type_name);
+ if (local_sym != null) {
+ if (sym != null) {
+ Report.error (type.source_reference, "`%s' is an ambiguous reference between `%s' and `%s'".printf (type.type_name, sym.get_full_name (), local_sym.get_full_name ()));
+ return;
+ }
+ sym = local_sym;
+ }
+ }
+ }
+ if (sym == null) {
+ Report.error (type.source_reference, "The type name `%s' could not be found".printf (type.type_name));
+ return;
+ }
+ if (sym.node is TypeParameter) {
+ type.type_parameter = (TypeParameter) sym.node;
+ } else {
+ type.data_type = (DataType) sym.node;
+ }
+ } else {
+ var ns_symbol = root_symbol.lookup (type.namespace_name);
+ if (ns_symbol == null) {
+ type.error = true;
+ Report.error (type.source_reference, "The namespace name `%s' could not be found".printf (type.namespace_name));
+ return;
+ }
+
+ var sym = ns_symbol.lookup (type.type_name);
+ if (sym == null) {
+ Report.error (type.source_reference, "The type name `%s' does not exist in the namespace `%s'".printf (type.type_name, type.namespace_name));
+ return;
+ }
+ type.data_type = (DataType) sym.node;
+ }
+
+ if (type.pointer_level > 0) {
+ if (type.data_type == null) {
+ type.error = true;
+ Report.error (type.source_reference, "Pointer to `%s' not supported".printf (type.type_name));
+ return;
+ }
+ var referent_type = new TypeReference ();
+ referent_type.data_type = type.data_type;
+ referent_type.pointer_level = type.pointer_level - 1;
+
+ if (type.data_type.is_reference_type ()) {
+ referent_type.takes_ownership = type.takes_ownership;
+ }
+ type.data_type = referent_type.data_type.get_pointer ();
+ type.add_type_argument (referent_type);
+
+ visit_type_reference (referent_type);
+ }
+
+ /* check for array */
+ if (type.array_rank > 0) {
+ var element_type = new TypeReference ();
+ element_type.data_type = type.data_type;
+ element_type.type_parameter = type.type_parameter;
+ foreach (TypeReference type_arg in type.get_type_arguments ()) {
+ element_type.add_type_argument (type_arg);
+ }
+ type.remove_all_type_arguments ();
+
+ if (type.data_type != null) {
+ if (type.data_type.is_reference_type ()) {
+ element_type.takes_ownership = type.takes_ownership;
+ }
+ type.data_type = element_type.data_type.get_array (type.array_rank);
+ } else {
+ type.data_type = element_type.type_parameter.get_array (type.array_rank);
+ type.type_parameter = null;
+ }
+ type.add_type_argument (element_type);
+ }
+
+ if (type.data_type != null && !type.data_type.is_reference_type ()) {
+ /* reset takes_ownership and transfers_ownership of
+ * value-types for contexts where types are ref by
+ * default (field declarations and method return types)
+ */
+ type.takes_ownership = false;
+ type.transfers_ownership = false;
+ }
+ }
+}
diff --git a/vala/valathrowstatement.vala b/vala/valathrowstatement.vala
new file mode 100644
index 000000000..3a69ae520
--- /dev/null
+++ b/vala/valathrowstatement.vala
@@ -0,0 +1,73 @@
+/* valathrowstatement.vala
+ *
+ * Copyright (C) 2007 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;
+
+/**
+ * Represents a throw statement in the source code.
+ */
+public class Vala.ThrowStatement : Statement {
+ /**
+ * The error expression to throw.
+ */
+ public Expression error_expression {
+ get {
+ return _error_expression;
+ }
+ set {
+ _error_expression = value;
+ if (_error_expression != null) {
+ _error_expression.parent_node = this;
+ }
+ }
+ }
+
+ private Expression! _error_expression;
+
+ /**
+ * Creates a new throw statement.
+ *
+ * @param error_expression the error expression
+ * @param source_reference reference to source code
+ * @return newly created throw statement
+ */
+ public ThrowStatement (construct Expression! error_expression, construct SourceReference source_reference = null) {
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_throw_statement (this);
+
+ if (error_expression != null) {
+ error_expression.accept (visitor);
+
+ visitor.visit_end_full_expression (error_expression);
+ }
+
+ visitor.visit_end_throw_statement (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (error_expression == old_node) {
+ error_expression = (Expression) new_node;
+ }
+ }
+}
diff --git a/vala/valatrystatement.vala b/vala/valatrystatement.vala
new file mode 100644
index 000000000..b1a1ccf81
--- /dev/null
+++ b/vala/valatrystatement.vala
@@ -0,0 +1,66 @@
+/* valatrystatement.vala
+ *
+ * Copyright (C) 2007 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;
+
+/**
+ * Represents a try statement in the source code.
+ */
+public class Vala.TryStatement : Statement {
+ /**
+ * Specifies the body of the try statement.
+ */
+ public Block! body { get; set construct; }
+
+ /**
+ * Specifies the body of the optional finally clause.
+ */
+ public Block finally_body { get; set; }
+
+ private List<CatchClause> catch_clauses;
+
+ /**
+ * Creates a new try statement.
+ *
+ * @param body body of the try statement
+ * @param finally_body body of the optional finally clause
+ * @param source_reference reference to source code
+ * @return newly created try statement
+ */
+ public TryStatement (construct Block! body, construct Block finally_body, construct SourceReference source_reference = null) {
+ }
+
+ /**
+ * Appends the specified clause to the list of catch clauses.
+ *
+ * @param clause a catch clause
+ */
+ public void add_catch_clause (CatchClause! clause) {
+ catch_clauses.append (clause);
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_try_statement (this);
+
+ visitor.visit_end_try_statement (this);
+ }
+}
diff --git a/vala/valatypecheck.vala b/vala/valatypecheck.vala
new file mode 100644
index 000000000..bb9f605c7
--- /dev/null
+++ b/vala/valatypecheck.vala
@@ -0,0 +1,60 @@
+/* valatypecheck.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;
+
+/**
+ * Represents a type check (`is') expression in the source code.
+ */
+public class Vala.TypeCheck : Expression {
+ /**
+ * The expression to be checked.
+ */
+ public Expression! expression { get; set construct; }
+
+ /**
+ * The type to be matched against.
+ */
+ public TypeReference! type_reference { get; set construct; }
+
+ /**
+ * Creates a new type check expression.
+ *
+ * @param expr an expression
+ * @param type a data type
+ * @param source reference to source code
+ * @return newly created type check expression
+ */
+ public TypeCheck (Expression! expr, TypeReference! type, SourceReference source) {
+ expression = expr;
+ type_reference = type;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ expression.accept (visitor);
+
+ type_reference.accept (visitor);
+
+ visitor.visit_type_check (this);
+ }
+}
diff --git a/vala/valatypeofexpression.vala b/vala/valatypeofexpression.vala
new file mode 100644
index 000000000..9589a5433
--- /dev/null
+++ b/vala/valatypeofexpression.vala
@@ -0,0 +1,51 @@
+/* valatypeofexpression.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;
+
+/**
+ * Represents a typeof expression in the source code.
+ */
+public class Vala.TypeofExpression : Expression {
+ /**
+ * The type to be retrieved.
+ */
+ public TypeReference! type_reference { get; set construct; }
+
+ /**
+ * Creates a new typeof expression.
+ *
+ * @param type a data type
+ * @param source reference to source code
+ * @return newly created typeof expression
+ */
+ public TypeofExpression (TypeReference! type, SourceReference source) {
+ type_reference = type;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ type_reference.accept (visitor);
+
+ visitor.visit_typeof_expression (this);
+ }
+}
diff --git a/vala/valatypeparameter.vala b/vala/valatypeparameter.vala
new file mode 100644
index 000000000..46d1f35aa
--- /dev/null
+++ b/vala/valatypeparameter.vala
@@ -0,0 +1,104 @@
+/* valatypeparameter.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * Represents a generic type parameter in the source code.
+ */
+public class Vala.TypeParameter : CodeNode {
+ /**
+ * The parameter name.
+ */
+ public string! name { get; set construct; }
+
+ /**
+ * The generic type declaring this parameter.
+ */
+ public weak DataType type;
+
+ /* holds the array types of this type; each rank is a separate one */
+ /* FIXME: uses string because int does not work as key yet */
+ private HashTable<string,Array> array_types = new HashTable.full (str_hash, str_equal, g_free, g_object_unref);
+
+ /**
+ * Creates a new generic type parameter.
+ *
+ * @param name parameter name
+ * @param source reference to source code
+ * @return newly created generic type parameter
+ */
+ public TypeParameter (string! _name, SourceReference source) {
+ name = _name;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_type_parameter (this);
+ }
+
+ /**
+ * Returns the array type for elements of this type parameter.
+ *
+ * @param rank the rank the array should be of
+ * @return array type for this type parameter
+ */
+ public Array! get_array (int rank) {
+ Array array_type = (Array) array_types.lookup (rank.to_string ());
+
+ if (array_type == null) {
+ var new_array_type = new Array.with_type_parameter (this, rank, source_reference);
+ /* create a new Symbol */
+ new_array_type.symbol = new Symbol (new_array_type);
+ this.symbol.parent_symbol.add (new_array_type.name, new_array_type.symbol);
+
+ /* add internal length field */
+ new_array_type.symbol.add (new_array_type.get_length_field ().name, new_array_type.get_length_field ().symbol);
+ /* add internal resize method */
+ new_array_type.symbol.add (new_array_type.get_resize_method ().name, new_array_type.get_resize_method ().symbol);
+
+ /* link the array type to the same source as the container type */
+ new_array_type.source_reference = this.source_reference;
+
+ array_types.insert (rank.to_string (), new_array_type);
+
+ array_type = new_array_type;
+ }
+
+ return array_type;
+ }
+
+ /**
+ * Checks two type parameters for equality.
+ *
+ * @param param2 a type parameter
+ * @return true if this type parameter is equal to param2, false
+ * otherwise
+ */
+ public bool equals (TypeParameter! param2) {
+ // FIXME check whether the corresponding data type of one of the
+ // parameters is a base type of the corresponding data
+ // type of the other parameter and check along the path
+ // whether one parameter maps to the other
+ return true;
+ }
+}
diff --git a/vala/valatypereference.vala b/vala/valatypereference.vala
new file mode 100644
index 000000000..f3824ced4
--- /dev/null
+++ b/vala/valatypereference.vala
@@ -0,0 +1,389 @@
+/* valatypereference.vala
+ *
+ * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
+ *
+ * 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>
+ * Raffaele Sandrini <rasa@gmx.ch>
+ */
+
+using GLib;
+
+/**
+ * A reference to a data type. This is used to specify static types of
+ * expressions.
+ */
+public class Vala.TypeReference : CodeNode {
+ /**
+ * Specifies that the expression is a reference to a value type.
+ * References to value types are used in ref parameters.
+ */
+ public bool reference_to_value_type { get; set; }
+
+ /**
+ * Specifies that the expression transfers ownership of its value.
+ */
+ public bool transfers_ownership { get; set; }
+
+ /**
+ * Specifies that the expression assumes ownership if used as an lvalue
+ * in an assignment.
+ */
+ public bool takes_ownership { get; set; }
+
+ /**
+ * Specifies that the expression is a reference to a reference type.
+ * References to reference types are used in out parameters.
+ */
+ public bool is_out { get; set; }
+
+ /**
+ * Specifies that the expression is guaranteed not to be null.
+ */
+ public bool non_null { get; set; }
+
+ /**
+ * Specifies that the expression is known to be null.
+ */
+ public bool is_null { get; set; }
+
+ /**
+ * The referred data type.
+ */
+ public weak DataType data_type { get; set; }
+
+ /**
+ * The referred generic type parameter.
+ */
+ public TypeParameter type_parameter { get; set; }
+
+ /**
+ * Specifies that the expression transfers a floating reference.
+ */
+ public bool floating_reference { get; set; }
+
+ /**
+ * The name of the namespace containing the referred data type. May only
+ * be used with unresolved type references.
+ */
+ public string namespace_name { get; set; }
+
+ /**
+ * The name of the referred data type. May only be used with unresolved
+ * type references.
+ */
+ public string type_name { get; set; }
+
+ /**
+ * Specifies the rank of the array this reference is possibly referring to. "0" indicates no array.
+ * WARNING: This property may only be set by the parser and only be read by the symbol resolver.
+ */
+ public int array_rank { get; set; }
+
+ /**
+ * Specifies the level of the pointer if this is a pointer-type. "0" indicates no pointer-type.
+ * WARNING: This property may only be set by the parser and only be read by the symbol resolver.
+ */
+ public int pointer_level { get; set; }
+
+ /**
+ * The ref modifier has been specified, may only be used with unresolved
+ * type references.
+ */
+ public bool is_ref { get; set; }
+
+ /**
+ * The weak modifier has been specified. May only be used with
+ * unresolved type references.
+ */
+ public bool is_weak { get; set; }
+
+ private List<TypeReference> type_argument_list;
+
+ public TypeReference () {
+ }
+
+ /**
+ * Creates a new type reference.
+ *
+ * @param ns optional namespace name
+ * @param type_name type symbol name
+ * @param source reference to source code
+ * @return newly created type reference
+ */
+ public TypeReference.from_name (string ns, string! type, SourceReference source = null) {
+ namespace_name = ns;
+ type_name = type;
+ source_reference = source;
+ }
+
+ /**
+ * Creates a new type reference from a code expression.
+ *
+ * @param expr member access expression
+ * @param source reference to source code
+ * @return newly created type reference
+ */
+ public static ref TypeReference new_from_expression (Expression! expr) {
+ string ns = null;
+ string type_name = null;
+ if (expr is MemberAccess) {
+ TypeReference type_ref = null;
+
+ MemberAccess ma = (MemberAccess) expr;
+ if (ma.inner != null) {
+ if (ma.inner is MemberAccess) {
+ var simple = (MemberAccess) ma.inner;
+ type_ref = new TypeReference.from_name (simple.member_name, ma.member_name, ma.source_reference);
+ }
+ } else {
+ type_ref = new TypeReference.from_name (null, ma.member_name, ma.source_reference);
+ }
+
+ if (type_ref != null) {
+ var type_args = ma.get_type_arguments ();
+ foreach (TypeReference arg in type_args) {
+ type_ref.add_type_argument (arg);
+ }
+
+ return type_ref;
+ }
+ }
+
+ Report.error (expr.source_reference, "Type reference must be simple name or member access expression");
+ return null;
+ }
+
+ /**
+ * Appends the specified type as generic type argument.
+ *
+ * @param arg a type reference
+ */
+ public void add_type_argument (TypeReference! arg) {
+ type_argument_list.append (arg);
+ }
+
+ /**
+ * Returns a copy of the list of generic type arguments.
+ *
+ * @return type argument list
+ */
+ public ref List<weak TypeReference> get_type_arguments () {
+ return type_argument_list.copy ();
+ }
+
+ /**
+ * Removes all generic type arguments.
+ */
+ public void remove_all_type_arguments () {
+ type_argument_list = null;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ foreach (TypeReference type_arg in type_argument_list) {
+ type_arg.accept (visitor);
+ }
+
+ visitor.visit_type_reference (this);
+ }
+
+ /**
+ * Returns the name and qualifiers of this type as it is used in C code.
+ *
+ * @return the type string to be used in C code
+ */
+ public ref string get_cname (bool var_type = false, bool const_type = false) {
+ if (data_type == null && type_parameter == null) {
+ if (var_type) {
+ return "gpointer";
+ } else {
+ return "void";
+ }
+ }
+
+ string ptr;
+ string arr;
+ if (type_parameter != null || (!data_type.is_reference_type () && !reference_to_value_type)) {
+ ptr = "";
+ } else if ((data_type.is_reference_type () && !is_out) || reference_to_value_type) {
+ ptr = "*";
+ } else {
+ ptr = "**";
+ }
+ if (data_type != null) {
+ return data_type.get_cname (const_type).concat (ptr, arr, null);
+ } else if (type_parameter != null) {
+ return "gpointer".concat (ptr, arr, null);
+ } else {
+ /* raise error */
+ Report.error (source_reference, "unresolved type reference");
+ return null;
+ }
+ }
+
+ /**
+ * Returns the name and qualifiers of this type as it is used in C code
+ * in a const declaration.
+ *
+ * @return the type string to be used in C code const declarations
+ */
+ public ref string get_const_cname () {
+ string ptr;
+ DataType t;
+ /* FIXME: dirty hack to make constant arrays possible */
+ if (data_type is Array) {
+ t = ((Array) data_type).element_type;
+ } else {
+ t = data_type;
+ }
+ if (!t.is_reference_type ()) {
+ ptr = "";
+ } else {
+ ptr = "*";
+ }
+
+ return "const %s%s".printf (t.get_cname (), ptr);
+ }
+
+ /**
+ * Returns a user-readable name of the type corresponding to this type
+ * reference.
+ *
+ * @return display name
+ */
+ public ref string! to_string () {
+ if (data_type != null) {
+ return data_type.symbol.get_full_name ();
+ } else if (type_parameter != null) {
+ return type_parameter.name;
+ } else {
+ return "null";
+ }
+ }
+
+ /**
+ * Creates a shallow copy of this type reference.
+ *
+ * @return copy of this type reference
+ */
+ public ref TypeReference! copy () {
+ var result = new TypeReference ();
+ result.source_reference = source_reference;
+ result.reference_to_value_type = reference_to_value_type;
+ result.transfers_ownership = transfers_ownership;
+ result.takes_ownership = takes_ownership;
+ result.is_out = is_out;
+ result.non_null = non_null;
+ result.data_type = data_type;
+ result.type_parameter = type_parameter;
+ result.floating_reference = floating_reference;
+ result.namespace_name = namespace_name;
+ result.type_name = type_name;
+ result.array_rank = array_rank;
+ result.pointer_level = pointer_level;
+ result.is_ref = is_ref;
+ result.is_weak = is_weak;
+
+ foreach (TypeReference arg in type_argument_list) {
+ result.type_argument_list.append (arg.copy ());
+ }
+
+ return result;
+ }
+
+ /**
+ * Checks two type references for equality. May only be used with
+ * resolved type references.
+ *
+ * @param type2 a type reference
+ * @return true if this type reference is equal to type2, false
+ * otherwise
+ */
+ public bool equals (TypeReference! type2) {
+ if (type2.reference_to_value_type != reference_to_value_type) {
+ return false;
+ }
+ if (type2.transfers_ownership != transfers_ownership) {
+ return false;
+ }
+ if (type2.takes_ownership != takes_ownership) {
+ return false;
+ }
+ if (type2.is_out != is_out) {
+ return false;
+ }
+ if (type2.non_null != non_null) {
+ return false;
+ }
+ if (type2.data_type != data_type) {
+ return false;
+ }
+ if (type2.type_parameter != null || type_parameter != null) {
+ if (type2.type_parameter == null || type_parameter == null) {
+ return false;
+ }
+ if (!type2.type_parameter.equals (type_parameter)) {
+ return false;
+ }
+ }
+ if (type2.floating_reference != floating_reference) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks whether this type reference is at least as strict as the
+ * specified type reference type2.
+ *
+ * @param type2 a type reference
+ * @return true if this type reference is stricter or equal
+ */
+ public bool stricter (TypeReference! type2) {
+ if (type2.reference_to_value_type != reference_to_value_type) {
+ return false;
+ }
+ if (type2.transfers_ownership != transfers_ownership) {
+ return false;
+ }
+ if (type2.takes_ownership != takes_ownership) {
+ return false;
+ }
+ if (type2.is_out != is_out) {
+ return false;
+ }
+
+ if (type2.non_null && !non_null) {
+ return false;
+ }
+
+ if (type2.data_type != data_type) {
+ // FIXME: allow this type reference to refer to a
+ // subtype of the type type2 is referring to
+ return false;
+ }
+ if (type2.type_parameter != type_parameter) {
+ return false;
+ }
+ if (type2.floating_reference != floating_reference) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/vala/valatyperegisterfunction.vala b/vala/valatyperegisterfunction.vala
new file mode 100644
index 000000000..d8a3044af
--- /dev/null
+++ b/vala/valatyperegisterfunction.vala
@@ -0,0 +1,186 @@
+/* valatyperegisterfunction.vala
+ *
+ * Copyright (C) 2006-2007 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;
+
+/**
+ * C function to register a type at runtime.
+ */
+public abstract class Vala.TypeRegisterFunction {
+ private CCodeFragment declaration_fragment = new CCodeFragment ();
+
+ private CCodeFragment definition_fragment = new CCodeFragment ();
+
+ /**
+ * Constructs the C function from the specified type.
+ */
+ public void init_from_type (bool plugin = false) {
+ string type_id_name = "%s_type_id".printf (get_type_declaration ().get_lower_case_cname (null));
+
+ var type_block = new CCodeBlock ();
+ var cdecl = new CCodeDeclaration ("GType");
+ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (type_id_name, new CCodeConstant ("0")));
+ cdecl.modifiers = CCodeModifiers.STATIC;
+ if (!plugin) {
+ type_block.add_statement (cdecl);
+ } else {
+ definition_fragment.append (cdecl);
+ }
+
+ CCodeFunction fun;
+ if (!plugin) {
+ fun = new CCodeFunction ("%s_get_type".printf (get_type_declaration ().get_lower_case_cname (null)), "GType");
+ } else {
+ fun = new CCodeFunction ("%s_register_type".printf (get_type_declaration ().get_lower_case_cname (null)), "GType");
+ fun.add_parameter (new CCodeFormalParameter ("module", "GTypeModule *"));
+
+ var get_fun = new CCodeFunction ("%s_get_type".printf (get_type_declaration ().get_lower_case_cname (null)), "GType");
+
+ declaration_fragment.append (get_fun.copy ());
+
+ get_fun.block = new CCodeBlock ();
+ get_fun.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier (type_id_name)));
+
+ definition_fragment.append (get_fun);
+ }
+
+ var type_init = new CCodeBlock ();
+ var ctypedecl = new CCodeDeclaration ("const GTypeInfo");
+ ctypedecl.modifiers = CCodeModifiers.STATIC;
+ ctypedecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("g_define_type_info", new CCodeConstant ("{ sizeof (%s), (GBaseInitFunc) %s, (GBaseFinalizeFunc) NULL, (GClassInitFunc) %s, (GClassFinalizeFunc) NULL, NULL, %s, 0, (GInstanceInitFunc) %s }".printf (get_type_struct_name (), get_base_init_func_name (), get_class_init_func_name (), get_instance_struct_size (), get_instance_init_func_name ()))));
+ type_init.add_statement (ctypedecl);
+ CCodeFunctionCall reg_call;
+ if (!plugin) {
+ reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_register_static"));
+ } else {
+ reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_module_register_type"));
+ reg_call.add_argument (new CCodeIdentifier ("module"));
+ }
+ reg_call.add_argument (new CCodeIdentifier (get_parent_type_name ()));
+ reg_call.add_argument (new CCodeConstant ("\"%s\"".printf (get_type_declaration ().get_cname ())));
+ reg_call.add_argument (new CCodeIdentifier ("&g_define_type_info"));
+ reg_call.add_argument (new CCodeConstant (get_type_flags ()));
+ type_init.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (type_id_name), reg_call)));
+
+ type_init.add_statement (get_type_interface_init_statements ());
+
+ if (!plugin) {
+ var cond = new CCodeFunctionCall (new CCodeIdentifier ("G_UNLIKELY"));
+ cond.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (type_id_name), new CCodeConstant ("0")));
+ var cif = new CCodeIfStatement (cond, type_init);
+ type_block.add_statement (cif);
+ } else {
+ type_block = type_init;
+ }
+
+ type_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier (type_id_name)));
+
+ declaration_fragment.append (fun.copy ());
+
+ fun.block = type_block;
+
+ definition_fragment.append (fun);
+ }
+
+ /**
+ * Returns the data type to be registered.
+ *
+ * @return type to be registered
+ */
+ public abstract DataType! get_type_declaration ();
+
+ /**
+ * Returns the name of the type struct in C code.
+ *
+ * @return C struct name
+ */
+ public abstract ref string! get_type_struct_name ();
+
+ /**
+ * Returns the name of the base_init function in C code.
+ *
+ * @return C function name
+ */
+ public abstract ref string! get_base_init_func_name ();
+
+ /**
+ * Returns the name of the class_init function in C code.
+ *
+ * @return C function name
+ */
+ public abstract ref string! get_class_init_func_name ();
+
+ /**
+ * Returns the size of the instance struct in C code.
+ *
+ * @return C instance struct size
+ */
+ public abstract ref string! get_instance_struct_size ();
+
+ /**
+ * Returns the name of the instance_init function in C code.
+ *
+ * @return C function name
+ */
+ public abstract ref string! get_instance_init_func_name ();
+
+ /**
+ * Returns the name of the parent type in C code.
+ *
+ * @return C parent type name
+ */
+ public abstract ref string! get_parent_type_name ();
+
+ /**
+ * Returns the set of type flags to be applied when registering.
+ *
+ * @return type flags
+ */
+ public virtual string get_type_flags () {
+ return "0";
+ }
+
+ /**
+ * Returns additional C initialization statements to setup interfaces.
+ *
+ * @return C statements
+ */
+ public abstract ref CCodeFragment! get_type_interface_init_statements ();
+
+ /**
+ * Returns the declaration for this type register function in C code.
+ *
+ * @return C function declaration fragment
+ */
+ public CCodeFragment! get_declaration () {
+ return declaration_fragment;
+ }
+
+ /**
+ * Returns the definition for this type register function in C code.
+ *
+ * @return C function definition fragment
+ */
+ public CCodeFragment! get_definition () {
+ return definition_fragment;
+ }
+}
diff --git a/vala/valaunaryexpression.vala b/vala/valaunaryexpression.vala
new file mode 100644
index 000000000..2ecf8a2b5
--- /dev/null
+++ b/vala/valaunaryexpression.vala
@@ -0,0 +1,87 @@
+/* valaunaryexpression.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;
+
+/**
+ * Represents an expression with one operand in the source code.
+ *
+ * Supports +, -, !, ~, ref, out.
+ */
+public class Vala.UnaryExpression : Expression {
+ /**
+ * The unary operator.
+ */
+ public UnaryOperator operator { get; set; }
+
+ /**
+ * The operand.
+ */
+ public Expression! inner {
+ get {
+ return _inner;
+ }
+ set construct {
+ _inner = value;
+ _inner.parent_node = this;
+ }
+ }
+
+ private Expression! _inner;
+
+ /**
+ * Creates a new unary expression.
+ *
+ * @param op unary operator
+ * @param inner operand
+ * @param source reference to source code
+ * @return newly created binary expression
+ */
+ public UnaryExpression (UnaryOperator op, Expression! _inner, SourceReference source) {
+ operator = op;
+ inner = _inner;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ inner.accept (visitor);
+
+ visitor.visit_unary_expression (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (inner == old_node) {
+ inner = (Expression) new_node;
+ }
+ }
+}
+
+public enum Vala.UnaryOperator {
+ PLUS,
+ MINUS,
+ LOGICAL_NEGATION,
+ BITWISE_COMPLEMENT,
+ INCREMENT,
+ DECREMENT,
+ REF,
+ OUT
+}
diff --git a/vala/valavariabledeclarator.vala b/vala/valavariabledeclarator.vala
new file mode 100644
index 000000000..321a5b5d7
--- /dev/null
+++ b/vala/valavariabledeclarator.vala
@@ -0,0 +1,111 @@
+/* valavariabledeclarator.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;
+
+/**
+ * Represents a variable declarator in the source code.
+ */
+public class Vala.VariableDeclarator : CodeNode, Invokable {
+ /**
+ * The variable name.
+ */
+ public string! name { get; set construct; }
+
+ /**
+ * The optional initializer expression.
+ */
+ public Expression initializer {
+ get {
+ return _initializer;
+ }
+ set {
+ _initializer = value;
+ if (_initializer != null) {
+ _initializer.parent_node = this;
+ }
+ }
+ }
+
+ /**
+ * The variable type.
+ */
+ public TypeReference type_reference { get; set; }
+
+ private Expression _initializer;
+
+ /**
+ * Creates a new variable declarator.
+ *
+ * @param name name of the variable
+ * @param init optional initializer expression
+ * @param source reference to source code
+ * @return newly created variable declarator
+ */
+ public VariableDeclarator (string! _name, Expression init = null, SourceReference source = null) {
+ name = _name;
+ initializer = init;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ if (initializer != null) {
+ initializer.accept (visitor);
+
+ visitor.visit_end_full_expression (initializer);
+ }
+
+ if (type_reference != null) {
+ type_reference.accept (visitor);
+ }
+
+ visitor.visit_variable_declarator (this);
+ }
+
+ public ref List<weak FormalParameter> get_parameters () {
+ if (!is_invokable ()) {
+ return null;
+ }
+
+ var cb = (Callback) type_reference.data_type;
+ return cb.get_parameters ();
+ }
+
+ public TypeReference get_return_type () {
+ if (!is_invokable ()) {
+ return null;
+ }
+
+ var cb = (Callback) type_reference.data_type;
+ return cb.return_type;
+ }
+
+ public bool is_invokable () {
+ return (type_reference.data_type is Callback);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (initializer == old_node) {
+ initializer = (Expression) new_node;
+ }
+ }
+}
diff --git a/vala/valawhilestatement.vala b/vala/valawhilestatement.vala
new file mode 100644
index 000000000..ea22ea8db
--- /dev/null
+++ b/vala/valawhilestatement.vala
@@ -0,0 +1,78 @@
+/* valawhilestatement.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;
+
+/**
+ * Represents a while iteration statement in the source code.
+ */
+public class Vala.WhileStatement : Statement {
+ /**
+ * Specifies the loop condition.
+ */
+ public Expression! condition {
+ get {
+ return _condition;
+ }
+ set construct {
+ _condition = value;
+ _condition.parent_node = this;
+ }
+ }
+
+ /**
+ * Specifies the loop body.
+ */
+ public Statement body { get; set; }
+
+ private Expression! _condition;
+
+ /**
+ * Creates a new while statement.
+ *
+ * @param cond loop condition
+ * @param body loop body
+ * @param source reference to source code
+ * @return newly created while statement
+ */
+ public WhileStatement (Expression! cond, Statement! _body, SourceReference source) {
+ condition = cond;
+ body = _body;
+ source_reference = source;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ condition.accept (visitor);
+
+ visitor.visit_end_full_expression (condition);
+
+ body.accept (visitor);
+
+ visitor.visit_while_statement (this);
+ }
+
+ public override void replace (CodeNode! old_node, CodeNode! new_node) {
+ if (condition == old_node) {
+ condition = (Expression) new_node;
+ }
+ }
+}