[vala] Support conditional compilation
- From: Jürg Billeter <juergbi src gnome org>
- To: svn-commits-list gnome org
- Subject: [vala] Support conditional compilation
- Date: Fri, 3 Apr 2009 03:40:28 -0400 (EDT)
commit 3f0e7474f8cb772cdd7e19f1e062d4706f8e598b
Author: Jürg Billeter <j bitron ch>
Date: Fri Apr 3 09:37:00 2009 +0200
Support conditional compilation
Add -D SYMBOL commandline option to define conditional symbols.
Support precondition directives #if, #elif, #else, and #endif.
Fixes bug 434515.
---
compiler/valacompiler.vala | 10 ++
vala/valacodecontext.vala | 10 ++
vala/valascanner.vala | 263 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 283 insertions(+), 0 deletions(-)
diff --git a/compiler/valacompiler.vala b/compiler/valacompiler.vala
index 6becda9..0506388 100644
--- a/compiler/valacompiler.vala
+++ b/compiler/valacompiler.vala
@@ -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) {
diff --git a/vala/valacodecontext.vala b/vala/valacodecontext.vala
index abf1719..3babfa8 100644
--- a/vala/valacodecontext.vala
+++ b/vala/valacodecontext.vala
@@ -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;
diff --git a/vala/valascanner.vala b/vala/valascanner.vala
index 383186c..068cff7 100644
--- a/vala/valascanner.vala
+++ b/vala/valascanner.vala
@@ -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;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]