From: Rico Tzschichholz Date: Wed, 13 Mar 2019 07:40:04 +0000 (+0100) Subject: Support `define' expressions in global scope of source files X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=refs%2Fkeep-around%2F96ae8699bda464243bb0226eb180d7f5d0797cb8;p=thirdparty%2Fvala.git Support `define' expressions in global scope of source files Fixes https://gitlab.gnome.org/GNOME/vala/issues/765 --- 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 features = new HashSet (str_hash, str_equal); + Set defines = new HashSet (str_hash, str_equal); Set declarations = new HashSet (str_hash, str_equal); Set definitions = new HashSet (str_hash, str_equal); Set includes = new HashSet (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 + */ + +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? 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 current_using_directives { get; set; default = new ArrayList (); } private List nodes = new ArrayList (); + private List defines = new ArrayList (); 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 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 "`/'";