Merge pull request #35407 from neikeq/issue-27285

Add dummy preprocessor for the C# script class parser
This commit is contained in:
Ignacio Roldán Etcheverry 2020-01-21 20:39:23 +01:00 committed by GitHub
commit 24960e2254
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 95 additions and 4 deletions

View file

@ -81,7 +81,12 @@ namespace GodotTools
}
}
ScriptClassParser.ParseFileOrThrow(projectIncludeFile, out var classes);
Error parseError = ScriptClassParser.ParseFile(projectIncludeFile, out var classes, out string errorStr);
if (parseError != Error.Ok)
{
GD.PushError($"Failed to determine namespace and class for script: {projectIncludeFile}. Parse error: {errorStr ?? parseError.ToString()}");
continue;
}
string searchName = System.IO.Path.GetFileNameWithoutExtension(projectIncludeFile);

View file

@ -27,12 +27,15 @@ namespace GodotTools.Internals
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern Error internal_ParseFile(string filePath, Array<Dictionary> classes, out string errorStr);
public static void ParseFileOrThrow(string filePath, out IEnumerable<ClassDecl> classes)
public static Error ParseFile(string filePath, out IEnumerable<ClassDecl> classes, out string errorStr)
{
var classesArray = new Array<Dictionary>();
var error = internal_ParseFile(filePath, classesArray, out string errorStr);
var error = internal_ParseFile(filePath, classesArray, out errorStr);
if (error != Error.Ok)
throw new Exception($"Failed to determine namespace and class for script: {filePath}. Parse error: {errorStr ?? error.ToString()}");
{
classes = null;
return error;
}
var classesList = new List<ClassDecl>();
@ -47,6 +50,8 @@ namespace GodotTools.Internals
}
classes = classesList;
return Error.Ok;
}
}
}

View file

@ -631,6 +631,85 @@ Error ScriptClassParser::parse(const String &p_code) {
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) {
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." :
"Failed to read file: '" + p_filepath + "'.");
run_dummy_preprocessor(source);
return parse(source);
}