]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
Support conditional compilation
authorJürg Billeter <j@bitron.ch>
Fri, 3 Apr 2009 07:37:00 +0000 (09:37 +0200)
committerJürg Billeter <j@bitron.ch>
Fri, 3 Apr 2009 07:37:00 +0000 (09:37 +0200)
Add -D SYMBOL commandline option to define conditional symbols.
Support precondition directives #if, #elif, #else, and #endif.
Fixes bug 434515.

compiler/valacompiler.vala
vala/valacodecontext.vala
vala/valascanner.vala

index 6becda937b22be5fb21da4392404365122aa1e94..0506388bace5916216c82fc4ba9eb62cd22c8ac0 100644 (file)
@@ -58,6 +58,9 @@ class Vala.Compiler {
        static string[] cc_options;
        static string dump_tree;
        static bool save_temps;
+       [CCode (array_length = false, array_null_terminated = true)]
+       [NoArrayLength]
+       static string[] defines;
        static bool quiet_mode;
 
        private CodeContext context;
@@ -76,6 +79,7 @@ class Vala.Compiler {
                { "output", 'o', 0, OptionArg.FILENAME, ref output, "Place output in file FILE", "FILE" },
                { "debug", 'g', 0, OptionArg.NONE, ref debug, "Produce debug information", null },
                { "thread", 0, 0, OptionArg.NONE, ref thread, "Enable multithreading support", null },
+               { "define", 'D', 0, OptionArg.STRING_ARRAY, ref defines, "Define SYMBOL", "SYMBOL..." },
                { "disable-assert", 0, 0, OptionArg.NONE, ref disable_assert, "Disable assertions", null },
                { "enable-checking", 0, 0, OptionArg.NONE, ref enable_checking, "Enable additional run-time checks", null },
                { "enable-deprecated", 0, 0, OptionArg.NONE, ref deprecated, "Enable deprecated features", null },
@@ -188,6 +192,12 @@ class Vala.Compiler {
                context.thread = thread;
                context.save_temps = save_temps;
 
+               if (defines != null) {
+                       foreach (string define in defines) {
+                               context.add_define (define);
+                       }
+               }
+
                int glib_major = 2;
                int glib_minor = 12;
                if (target_glib != null && target_glib.scanf ("%d.%d", out glib_major, out glib_minor) != 2) {
index abf171925a1951a9560547204999f2361a044293..3babfa81f3a8e7ba4c4baebd17f7821d5f372b82 100644 (file)
@@ -171,6 +171,8 @@ public class Vala.CodeContext {
 
        private Gee.List<string> packages = new ArrayList<string> (str_equal);
 
+       private Set<string> defines = new HashSet<string> (str_hash, str_equal);
+
        static StaticPrivate context_stack_key = StaticPrivate ();
 
        /**
@@ -298,6 +300,14 @@ public class Vala.CodeContext {
                }
        }
 
+       public void add_define (string define) {
+               defines.add (define);
+       }
+
+       public bool is_defined (string define) {
+               return (define in defines);
+       }
+
        public string? get_package_path (string pkg, string[] vapi_directories) {
                string basename = "%s.vapi".printf (pkg);
                string filename = null;
index 383186c15df8ff9088401df003fc37eb3e5ea7c0..068cff7976e972b97c3395a99154bbe3a0ea957d 100644 (file)
@@ -37,6 +37,14 @@ public class Vala.Scanner {
 
        string _comment;
 
+       Conditional[] conditional_stack;
+
+       struct Conditional {
+               public bool matched;
+               public bool else_found;
+               public bool skip_section;
+       }
+
        public Scanner (SourceFile source_file) {
                this.source_file = source_file;
 
@@ -776,17 +784,272 @@ public class Vala.Scanner {
                return true;
        }
 
+       bool pp_whitespace () {
+               bool found = false;
+               while (current < end && current[0] == ' ') {
+                       found = true;
+                       current++;
+                       column++;
+               }
+               return found;
+       }
+
+       void pp_directive () {
+               do {
+                       current++;
+                       column++;
+               } while (current < end && current[0] == ' ');
+
+               char* begin = current;
+               int len = 0;
+               while (current < end && current[0].isalnum ()) {
+                       current++;
+                       column++;
+                       len++;
+               }
+
+               if (len == 2 && matches (begin, "if")) {
+                       parse_pp_if ();
+               } else if (len == 4 && matches (begin, "elif")) {
+                       parse_pp_elif ();
+               } else if (len == 4 && matches (begin, "else")) {
+                       parse_pp_else ();
+               } else if (len == 5 && matches (begin, "endif")) {
+                       parse_pp_endif ();
+               } else {
+                       Report.error (new SourceReference (source_file, line, column - len, line, column), "syntax error, invalid preprocessing directive");
+               }
+
+               if (conditional_stack.length > 0
+                   && conditional_stack[conditional_stack.length - 1].skip_section) {
+                       // skip lines until next preprocessing directive
+                       bool bol = false;
+                       while (current < end) {
+                               if (bol && current[0] == '#') {
+                                       return;
+                               }
+                               if (current[0] == '\n') {
+                                       line++;
+                                       column = 0;
+                                       bol = true;
+                               } else if (current[0] != ' ') {
+                                       bol = false;
+                               }
+                               current++;
+                               column++;
+                       }
+               }
+       }
+
+       void pp_eol () {
+               pp_whitespace ();
+               if (current >= end || current[0] != '\n') {
+                       Report.error (new SourceReference (source_file, line, column, line, column), "syntax error, expected newline");
+               }
+       }
+
+       void parse_pp_if () {
+               pp_whitespace ();
+
+               bool condition = parse_pp_expression ();
+
+               pp_eol ();
+
+               conditional_stack += Conditional ();
+
+               if (condition && (conditional_stack.length == 1 || !conditional_stack[conditional_stack.length - 2].skip_section)) {
+                       // condition true => process code within if
+                       conditional_stack[conditional_stack.length - 1].matched = true;
+               } else {
+                       // skip lines until next preprocessing directive
+                       conditional_stack[conditional_stack.length - 1].skip_section = true;
+               }
+       }
+
+       void parse_pp_elif () {
+               pp_whitespace ();
+
+               bool condition = parse_pp_expression ();
+
+               pp_eol ();
+
+               if (conditional_stack.length == 0 || conditional_stack[conditional_stack.length - 1].else_found) {
+                       Report.error (new SourceReference (source_file, line, column, line, column), "syntax error, unexpected #elif");
+                       return;
+               }
+
+               if (condition && !conditional_stack[conditional_stack.length - 1].matched
+                   && (conditional_stack.length == 1 || !conditional_stack[conditional_stack.length - 2].skip_section)) {
+                       // condition true => process code within if
+                       conditional_stack[conditional_stack.length - 1].matched = true;
+                       conditional_stack[conditional_stack.length - 1].skip_section = false;
+               } else {
+                       // skip lines until next preprocessing directive
+                       conditional_stack[conditional_stack.length - 1].skip_section = true;
+               }
+       }
+
+       void parse_pp_else () {
+               pp_eol ();
+
+               if (conditional_stack.length == 0 || conditional_stack[conditional_stack.length - 1].else_found) {
+                       Report.error (new SourceReference (source_file, line, column, line, column), "syntax error, unexpected #else");
+                       return;
+               }
+
+               if (!conditional_stack[conditional_stack.length - 1].matched
+                   && (conditional_stack.length == 1 || !conditional_stack[conditional_stack.length - 2].skip_section)) {
+                       // condition true => process code within if
+                       conditional_stack[conditional_stack.length - 1].matched = true;
+                       conditional_stack[conditional_stack.length - 1].skip_section = false;
+               } else {
+                       // skip lines until next preprocessing directive
+                       conditional_stack[conditional_stack.length - 1].skip_section = true;
+               }
+       }
+
+       void parse_pp_endif () {
+               pp_eol ();
+
+               if (conditional_stack.length == 0) {
+                       Report.error (new SourceReference (source_file, line, column, line, column), "syntax error, unexpected #endif");
+                       return;
+               }
+
+               conditional_stack.length--;
+       }
+
+       bool parse_pp_symbol () {
+               int len = 0;
+               while (current < end && is_ident_char (current[0])) {
+                       current++;
+                       column++;
+                       len++;
+               }
+
+               if (len == 0) {
+                       Report.error (new SourceReference (source_file, line, column, line, column), "syntax error, expected identifier");
+                       return false;
+               }
+
+               string identifier = ((string) (current - len)).ndup (len);
+               bool defined;
+               if (identifier == "true") {
+                       defined = true;
+               } else if (identifier == "false") {
+                       defined = false;
+               } else {
+                       defined = source_file.context.is_defined (identifier);
+               }
+
+               return defined;
+       }
+
+       bool parse_pp_primary_expression () {
+               if (current >= end) {
+                       Report.error (new SourceReference (source_file, line, column, line, column), "syntax error, expected identifier");
+               } else if (is_ident_char (current[0])) {
+                       return parse_pp_symbol ();
+               } else if (current[0] == '(') {
+                       current++;
+                       column++;
+                       pp_whitespace ();
+                       bool result = parse_pp_expression ();
+                       pp_whitespace ();
+                       if (current < end && current[0] ==  ')') {
+                               current++;
+                               column++;
+                       } else {
+                               Report.error (new SourceReference (source_file, line, column, line, column), "syntax error, expected `)'");
+                       }
+                       return result;
+               } else {
+                       Report.error (new SourceReference (source_file, line, column, line, column), "syntax error, expected identifier");
+               }
+               return false;
+       }
+
+       bool parse_pp_unary_expression () {
+               if (current < end && current[0] == '!') {
+                       current++;
+                       column++;
+                       pp_whitespace ();
+                       return !parse_pp_unary_expression ();
+               }
+
+               return parse_pp_primary_expression ();
+       }
+
+       bool parse_pp_equality_expression () {
+               bool left = parse_pp_unary_expression ();
+               pp_whitespace ();
+               while (true) {
+                       if (current < end - 1 && current[0] == '=' && current[1] == '=') {
+                               current += 2;
+                               column += 2;
+                               pp_whitespace ();
+                               bool right = parse_pp_unary_expression ();
+                               left = (left == right);
+                       } else if (current < end - 1 && current[0] == '!' && current[1] == '=') {
+                               current += 2;
+                               column += 2;
+                               pp_whitespace ();
+                               bool right = parse_pp_unary_expression ();
+                               left = (left != right);
+                       } else {
+                               break;
+                       }
+               }
+               return left;
+       }
+
+       bool parse_pp_and_expression () {
+               bool left = parse_pp_equality_expression ();
+               pp_whitespace ();
+               while (current < end - 1 && current[0] == '&' && current[1] == '&') {
+                       current += 2;
+                       column += 2;
+                       pp_whitespace ();
+                       bool right = parse_pp_equality_expression ();
+                       left = left && right;
+               }
+               return left;
+       }
+
+       bool parse_pp_or_expression () {
+               bool left = parse_pp_and_expression ();
+               pp_whitespace ();
+               while (current < end - 1 && current[0] == '|' && current[1] == '|') {
+                       current += 2;
+                       column += 2;
+                       pp_whitespace ();
+                       bool right = parse_pp_and_expression ();
+                       left = left || right;
+               }
+               return left;
+       }
+
+       bool parse_pp_expression () {
+               return parse_pp_or_expression ();
+       }
+
        bool whitespace () {
                bool found = false;
+               bool bol = (column == 1);
                while (current < end && current[0].isspace ()) {
                        if (current[0] == '\n') {
                                line++;
                                column = 0;
+                               bol = true;
                        }
                        found = true;
                        current++;
                        column++;
                }
+               if (bol && current[0] == '#') {
+                       pp_directive ();
+                       return true;
+               }
                return found;
        }