Browse Source

Add dummy preprocessor for the C# script class parser

No attempts are made at conditional compilation. The main if branch is always assumed to be true.
Ignacio Etcheverry 5 years ago
parent
commit
378fc592b1
1 changed files with 81 additions and 0 deletions
  1. 81 0
      modules/mono/editor/script_class_parser.cpp

+ 81 - 0
modules/mono/editor/script_class_parser.cpp

@@ -631,6 +631,85 @@ Error ScriptClassParser::parse(const String &p_code) {
 	return OK;
 	return OK;
 }
 }
 
 
+static String get_preprocessor_directive(const String &p_line, int p_from) {
+	CRASH_COND(p_line[p_from] != '#');
+	p_from++;
+	int i = p_from;
+	while (i < p_line.length() && p_line[i] != ' ' && p_line[i] != '\t') {
+		i++;
+	}
+	return p_line.substr(p_from, i - p_from);
+}
+
+static void run_dummy_preprocessor(String &r_source) {
+
+	Vector<String> lines = r_source.split("\n", /* p_allow_empty: */ true);
+
+	bool *include_lines = memnew_arr(bool, lines.size());
+
+	int if_level = -1;
+	Vector<bool> is_branch_being_compiled;
+
+	for (int i = 0; i < lines.size(); i++) {
+		const String &line = lines[i];
+
+		const int line_len = line.length();
+
+		int j = 0;
+		while (j < line_len) {
+			if (line[j] != ' ' && line[j] != '\t') {
+				if (line[j] == '#') {
+					// First non-whitespace char of the line is '#'
+					include_lines[i] = false;
+
+					String directive = get_preprocessor_directive(line, j);
+
+					if (directive == "if") {
+						if_level++;
+						is_branch_being_compiled.push_back(if_level == 0 || is_branch_being_compiled[if_level - 1]);
+					} else if (directive == "elif") {
+						ERR_CONTINUE_MSG(if_level == -1, "Found unexpected '#elif' directive.");
+						is_branch_being_compiled.write[if_level] = false;
+					} else if (directive == "else") {
+						ERR_CONTINUE_MSG(if_level == -1, "Found unexpected '#else' directive.");
+						is_branch_being_compiled.write[if_level] = false;
+					} else if (directive == "endif") {
+						ERR_CONTINUE_MSG(if_level == -1, "Found unexpected '#endif' directive.");
+						is_branch_being_compiled.remove(if_level);
+						if_level--;
+					}
+
+					break;
+				} else {
+					// First non-whitespace char of the line is not '#'
+					include_lines[i] = if_level == -1 || is_branch_being_compiled[if_level];
+					break;
+				}
+			}
+
+			j++;
+		}
+
+		if (j == line_len) {
+			// Loop ended without finding a non-whitespace character.
+			// Either the line was empty or it only contained whitespaces.
+			include_lines[i] = if_level == -1 || is_branch_being_compiled[if_level];
+		}
+	}
+
+	r_source.clear();
+
+	// Custom join ignoring lines removed by the preprocessor
+	for (int i = 0; i < lines.size(); i++) {
+		if (i > 0 && include_lines[i - 1])
+			r_source += '\n';
+
+		if (include_lines[i]) {
+			r_source += lines[i];
+		}
+	}
+}
+
 Error ScriptClassParser::parse_file(const String &p_filepath) {
 Error ScriptClassParser::parse_file(const String &p_filepath) {
 
 
 	String source;
 	String source;
@@ -643,6 +722,8 @@ Error ScriptClassParser::parse_file(const String &p_filepath) {
 											" Please ensure that scripts are saved in valid UTF-8 unicode." :
 											" Please ensure that scripts are saved in valid UTF-8 unicode." :
 					"Failed to read file: '" + p_filepath + "'.");
 					"Failed to read file: '" + p_filepath + "'.");
 
 
+	run_dummy_preprocessor(source);
+
 	return parse(source);
 	return parse(source);
 }
 }