[vala/wip/defines: 154/154] Support `define' expressions in global scope of source files



commit 96ae8699bda464243bb0226eb180d7f5d0797cb8
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Wed Mar 13 08:40:04 2019 +0100

    Support `define' expressions in global scope of source files
    
    Fixes https://gitlab.gnome.org/GNOME/vala/issues/765

 ccode/valaccodefile.vala         | 19 ++++++++----
 codegen/valaccodeattribute.vala  |  4 ++-
 codegen/valaccodebasemodule.vala | 16 ++++++++++
 tests/Makefile.am                |  1 +
 tests/parser/define.vala         | 12 ++++++++
 vala/Makefile.am                 |  1 +
 vala/valacodevisitor.vala        |  8 +++++
 vala/valadefine.vala             | 63 ++++++++++++++++++++++++++++++++++++++++
 vala/valaparser.vala             | 24 +++++++++++++++
 vala/valascanner.vala            |  9 +++++-
 vala/valasourcefile.vala         | 22 ++++++++++++++
 vala/valatokentype.vala          |  2 ++
 12 files changed, 173 insertions(+), 8 deletions(-)
---
diff --git a/ccode/valaccodefile.vala b/ccode/valaccodefile.vala
index cf4870267..30d7eca5b 100644
--- a/ccode/valaccodefile.vala
+++ b/ccode/valaccodefile.vala
@@ -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 ();
diff --git a/codegen/valaccodeattribute.vala b/codegen/valaccodeattribute.vala
index 316570273..5b9f96b8b 100644
--- a/codegen/valaccodeattribute.vala
+++ b/codegen/valaccodeattribute.vala
@@ -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;
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 1349a20aa..273dded01 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -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;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 011fefa1a..96d1fa931 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -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
index 000000000..dbc47f850
--- /dev/null
+++ b/tests/parser/define.vala
@@ -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;
diff --git a/vala/Makefile.am b/vala/Makefile.am
index 57c758fdc..d7b42cd20 100644
--- a/vala/Makefile.am
+++ b/vala/Makefile.am
@@ -63,6 +63,7 @@ libvala_la_VALASOURCES = \
        valacreationmethod.vala \
        valadatatype.vala \
        valadeclarationstatement.vala \
+       valadefine.vala \
        valadelegate.vala \
        valadelegatedestroyfield.vala \
        valadelegatetargetfield.vala \
diff --git a/vala/valacodevisitor.vala b/vala/valacodevisitor.vala
index d961f85e9..59d825b0d 100644
--- a/vala/valacodevisitor.vala
+++ b/vala/valacodevisitor.vala
@@ -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
index 000000000..07807d88a
--- /dev/null
+++ b/vala/valadefine.vala
@@ -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;
+       }
+}
diff --git a/vala/valaparser.vala b/vala/valaparser.vala
index 0a424333a..418e99e8b 100644
--- a/vala/valaparser.vala
+++ b/vala/valaparser.vala
@@ -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 ();
diff --git a/vala/valascanner.vala b/vala/valascanner.vala
index 718b65471..293cf6efd 100644
--- a/vala/valascanner.vala
+++ b/vala/valascanner.vala
@@ -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;
diff --git a/vala/valasourcefile.vala b/vala/valasourcefile.vala
index 2e270a06c..1a387631d 100644
--- a/vala/valasourcefile.vala
+++ b/vala/valasourcefile.vala
@@ -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);
                }
diff --git a/vala/valatokentype.vala b/vala/valatokentype.vala
index 75cf92e6c..aee2cc93a 100644
--- a/vala/valatokentype.vala
+++ b/vala/valatokentype.vala
@@ -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 "`/'";


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