]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
Support `define' expressions in global scope of source files wip/defines 96ae8699bda464243bb0226eb180d7f5d0797cb8 54/head
authorRico Tzschichholz <ricotz@ubuntu.com>
Wed, 13 Mar 2019 07:40:04 +0000 (08:40 +0100)
committerRico Tzschichholz <ricotz@ubuntu.com>
Sun, 6 Oct 2019 15:57:44 +0000 (17:57 +0200)
Fixes https://gitlab.gnome.org/GNOME/vala/issues/765

12 files changed:
ccode/valaccodefile.vala
codegen/valaccodeattribute.vala
codegen/valaccodebasemodule.vala
tests/Makefile.am
tests/parser/define.vala [new file with mode: 0644]
vala/Makefile.am
vala/valacodevisitor.vala
vala/valadefine.vala [new file with mode: 0644]
vala/valaparser.vala
vala/valascanner.vala
vala/valasourcefile.vala
vala/valatokentype.vala

index cf4870267170ec4b6cc74ecad235035137a917ae..30d7eca5b82d275c1d8494bf55f93ca56e814dfa 100644 (file)
@@ -26,12 +26,12 @@ public class Vala.CCodeFile {
 
        public weak SourceFile? file { get; private set; }
 
-       Set<string> features = new HashSet<string> (str_hash, str_equal);
+       Set<string> defines = new HashSet<string> (str_hash, str_equal);
        Set<string> declarations = new HashSet<string> (str_hash, str_equal);
        Set<string> definitions = new HashSet<string> (str_hash, str_equal);
        Set<string> includes = new HashSet<string> (str_hash, str_equal);
        CCodeFragment comments = new CCodeFragment ();
-       CCodeFragment feature_test_macros = new CCodeFragment ();
+       CCodeFragment define_directives = new CCodeFragment ();
        CCodeFragment include_directives = new CCodeFragment ();
        CCodeFragment type_declaration = new CCodeFragment ();
        CCodeFragment type_definition = new CCodeFragment ();
@@ -55,10 +55,17 @@ public class Vala.CCodeFile {
                comments.append (comment);
        }
 
+       public void add_define (CCodeDefine node) {
+               if (!(node.name in defines)) {
+                       define_directives.append (node);
+                       defines.add (node.name);
+               }
+       }
+
        public void add_feature_test_macro (string feature_test_macro) {
-               if (!(feature_test_macro in features)) {
-                       feature_test_macros.append (new CCodeDefine (feature_test_macro));
-                       features.add (feature_test_macro);
+               if (!(feature_test_macro in defines)) {
+                       define_directives.append (new CCodeDefine (feature_test_macro));
+                       defines.add (feature_test_macro);
                }
        }
 
@@ -156,7 +163,7 @@ public class Vala.CCodeFile {
 
                        comments.write (writer);
                        writer.write_newline ();
-                       feature_test_macros.write (writer);
+                       define_directives.write (writer);
                        writer.write_newline ();
                        include_directives.write (writer);
                        writer.write_newline ();
index 3165702738b8dc4ff08d7a06d6121c3b0f5d2af2..5b9f96b8b0b4336b8d8b31fbd00e8a1214bbf5fc 100644 (file)
@@ -682,7 +682,9 @@ public class Vala.CCodeAttribute : AttributeCache {
 
        private string get_default_name () {
                if (sym != null) {
-                       if (sym is Constant && !(sym is EnumValue)) {
+                       if (sym is Define) {
+                               return sym.name;
+                       } else if (sym is Constant && !(sym is EnumValue)) {
                                if (sym.parent_symbol is Block) {
                                        // local constant
                                        return sym.name;
index 1349a20aa076cd28f931e27ca20b38c0b36829e5..273dded01708859571dbb6529bd2ada47bb62d20 100644 (file)
@@ -1047,6 +1047,22 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                pop_line ();
        }
 
+       public override void visit_define (Define d) {
+               push_line (d.source_reference);
+
+               d.accept_children (this);
+
+               CCodeDefine cdefine;
+               if (d.value == null) {
+                       cdefine = new CCodeDefine (get_ccode_name (d));
+               } else {
+                       cdefine = new CCodeDefine.with_expression (get_ccode_name (d), get_cvalue (d.value));
+               }
+               cfile.add_define (cdefine);
+
+               pop_line ();
+       }
+
        public void generate_field_declaration (Field f, CCodeFile decl_space) {
                if (add_symbol_declaration (decl_space, f, get_ccode_name (f))) {
                        return;
index 011fefa1a03a0ba7435382c87816458eb530eee6..96d1fa9317e5dfc56ea010e09c78b58f79a951c5 100644 (file)
@@ -547,6 +547,7 @@ TESTS = \
        parser/creation-no-new.test \
        parser/creation-no-override.test \
        parser/creation-no-virtual.test \
+       parser/define.vala \
        parser/delegate-anonymous.test \
        parser/delegate-no-new.test \
        parser/destructor-class-exists.test \
diff --git a/tests/parser/define.vala b/tests/parser/define.vala
new file mode 100644 (file)
index 0000000..dbc47f8
--- /dev/null
@@ -0,0 +1,12 @@
+define ENABLE_SOMETHING;
+define G_LOG_DOMAIN = "vala", VALA_PI = 3.1415;
+
+void foo () {
+}
+
+define ENABLE_SOMETHING_ELSE;
+
+void main () {
+}
+
+define ENABLE_SOMETHING_DIFFERENT;
index 57c758fdce359560a7aad713449122b98459fbcc..d7b42cd209e5815b7d1dee8f2838022d668360e4 100644 (file)
@@ -63,6 +63,7 @@ libvala_la_VALASOURCES = \
        valacreationmethod.vala \
        valadatatype.vala \
        valadeclarationstatement.vala \
+       valadefine.vala \
        valadelegate.vala \
        valadelegatedestroyfield.vala \
        valadelegatetargetfield.vala \
index d961f85e93730a4777490e2df77ff5a82a249c1f..59d825b0d7ad1c274e7178365ab2e67053f1c5ff 100644 (file)
@@ -204,6 +204,14 @@ public abstract class Vala.CodeVisitor {
        public virtual void visit_using_directive (UsingDirective ns) {
        }
 
+       /**
+        * Visit operation called for defines.
+        *
+        * @param ns a define
+        */
+       public virtual void visit_define (Define d) {
+       }
+
        /**
         * Visit operation called for type references.
         *
diff --git a/vala/valadefine.vala b/vala/valadefine.vala
new file mode 100644 (file)
index 0000000..07807d8
--- /dev/null
@@ -0,0 +1,63 @@
+/* valadefine.vala
+ *
+ * Copyright (C) 2019  Rico Tzschichholz
+ *
+ * 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.1 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:
+ *     Rico Tzschichholz <ricotz@ubuntu.com>
+ */
+
+using GLib;
+
+/**
+ * Represents a define in the source code.
+ */
+public class Vala.Define : Constant {
+       /**
+        * Creates a new define.
+        *
+        * @param name  define name
+        * @param value define value
+        * @return      newly created define
+        */
+       public Define (string name, Expression? value, SourceReference? source_reference = null, Comment? comment = null) {
+               base (name, null, value, source_reference, comment);
+       }
+
+       public override void accept (CodeVisitor visitor) {
+               visitor.visit_define (this);
+       }
+
+       public override void accept_children (CodeVisitor visitor) {
+               if (value != null) {
+                       value.accept (visitor);
+               }
+       }
+
+       public override bool check (CodeContext context) {
+               if (checked) {
+                       return !error;
+               }
+
+               checked = true;
+
+               if (value != null) {
+                       value.check (context);
+               }
+
+               return !error;
+       }
+}
index 0a424333a1dedf8b11eadc8042b08202fd38123b..418e99e8b28175a263b44858a3db6c5cdb1b7af3 100644 (file)
@@ -190,6 +190,7 @@ public class Vala.Parser : CodeVisitor {
                case TokenType.CONSTRUCT:
                case TokenType.CONTINUE:
                case TokenType.DEFAULT:
+               case TokenType.DEFINE:
                case TokenType.DELEGATE:
                case TokenType.DELETE:
                case TokenType.DO:
@@ -2281,6 +2282,10 @@ public class Vala.Parser : CodeVisitor {
                }
 
                switch (current ()) {
+               case TokenType.DEFINE:
+                       rollback (begin);
+                       parse_define (parent);
+                       return;
                case TokenType.CONSTRUCT:
                        if (context.profile == Profile.GOBJECT) {
                                rollback (begin);
@@ -2557,6 +2562,25 @@ public class Vala.Parser : CodeVisitor {
                }
        }
 
+       void parse_define (Symbol parent) throws ParseError {
+               if (parent != context.root) {
+                       throw new ParseError.SYNTAX ("`define' expressions allowed only in root namespace");
+               }
+
+               expect (TokenType.DEFINE);
+               do {
+                       var begin = get_location ();
+                       var name = parse_identifier ();
+                       Expression? val = null;
+                       if (accept (TokenType.ASSIGN)) {
+                               val = parse_literal ();
+                       }
+                       var def = new Define (name, val, get_src (begin), comment);
+                       scanner.source_file.add_define (def);
+               } while (accept (TokenType.COMMA));
+               expect (TokenType.SEMICOLON);
+       }
+
        void parse_class_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
                var begin = get_location ();
                var access = parse_access_modifier ();
index 718b654717d07b37b7a87fb37360ef0da12296b5..293cf6efd61f21fa1c8f7f9a1bebd449f960580b 100644 (file)
@@ -424,7 +424,14 @@ public class Vala.Scanner {
                case 6:
                        switch (begin[0]) {
                        case 'd':
-                               if (matches (begin, "delete")) return TokenType.DELETE;
+                               switch (begin[2]) {
+                               case 'f':
+                                       if (matches (begin, "define")) return TokenType.DEFINE;
+                                       break;
+                               case 'l':
+                                       if (matches (begin, "delete")) return TokenType.DELETE;
+                                       break;
+                               }
                                break;
                        case 'e':
                                if (matches (begin, "extern")) return TokenType.EXTERN;
index 2e270a06c5ee9e3ef2d05796f1f97d4120d3f24b..1a387631d378d070e01931827f4bcf5b726b6774 100644 (file)
@@ -129,6 +129,7 @@ public class Vala.SourceFile {
        public List<UsingDirective> current_using_directives { get; set; default = new ArrayList<UsingDirective> (); }
 
        private List<CodeNode> nodes = new ArrayList<CodeNode> ();
+       private List<Define> defines = new ArrayList<Define> ();
 
        string? _relative_filename;
 
@@ -187,6 +188,24 @@ public class Vala.SourceFile {
                current_using_directives.add (ns);
        }
 
+       /**
+        * Adds the specified define to this source file.
+        *
+        * @param define a define
+        */
+       public void add_define (Define define) {
+               defines.add (define);
+       }
+
+       /**
+        * Returns the list of defines.
+        *
+        * @return define list
+        */
+       public List<Define> get_defines () {
+               return defines;
+       }
+
        /**
         * Adds the specified code node to this source file.
         *
@@ -214,6 +233,9 @@ public class Vala.SourceFile {
        }
 
        public void accept_children (CodeVisitor visitor) {
+               foreach (Define define in defines) {
+                       define.accept (visitor);
+               }
                foreach (CodeNode node in nodes) {
                        node.accept (visitor);
                }
index 75cf92e6c9b94793a63e11bbcf3ced053e3a0e9b..aee2cc93a70e9d77ef9cfd83619be61dd14eb763 100644 (file)
@@ -57,6 +57,7 @@ public enum Vala.TokenType {
        CONSTRUCT,
        CONTINUE,
        DEFAULT,
+       DEFINE,
        DELEGATE,
        DELETE,
        DIV,
@@ -190,6 +191,7 @@ public enum Vala.TokenType {
                case CONSTRUCT: return "`construct'";
                case CONTINUE: return "`continue'";
                case DEFAULT: return "`default'";
+               case DEFINE: return "`define'";
                case DELEGATE: return "`delegate'";
                case DELETE: return "`delete'";
                case DIV: return "`/'";