|
@@ -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);
|
|
}
|
|
}
|
|
|
|
|