Skip to content

Commit

Permalink
Merge pull request #2178 from ivan-mogilko/361--trivialpreprocelse
Browse files Browse the repository at this point in the history
Basic support for "#else" preprocessor in AGS script
  • Loading branch information
ivan-mogilko authored Oct 15, 2023
2 parents 8f7897c + 0056d83 commit 1ca7622
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 5 deletions.
25 changes: 21 additions & 4 deletions Compiler/preproc/preprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ namespace Preprocessor {
case ErrorCode::IfWithoutEndIf:
cc_error("Missing #endif");
break;
case ErrorCode::ElseIfWithoutIf:
cc_error("#else has no matching #if");
break;
case ErrorCode::MacroDoesNotExist:
case ErrorCode::MacroAlreadyExists:
case ErrorCode::MacroNameInvalid:
Expand Down Expand Up @@ -114,7 +117,7 @@ namespace Preprocessor {

bool includeCodeBlock = true;

if ((!_conditionalStatements.empty()) && !_conditionalStatements.back())
if ((!_conditionalStatements.empty()) && !_conditionalStatements.top())
{
includeCodeBlock = false;
}
Expand All @@ -140,12 +143,12 @@ namespace Preprocessor {
}
}

_conditionalStatements.push_back(includeCodeBlock);
_conditionalStatements.push(includeCodeBlock);
}

bool Preprocessor::DeletingCurrentLine()
{
return ((!_conditionalStatements.empty()) && !_conditionalStatements.back());
return ((!_conditionalStatements.empty()) && !_conditionalStatements.top());
}

String Preprocessor::GetNextWord(String &text, bool trimText, bool includeDots) {
Expand Down Expand Up @@ -231,11 +234,25 @@ namespace Preprocessor {
{
ProcessConditionalDirective(directive, line);
}
else if (directive == "else")
{
if (!_conditionalStatements.empty())
{
// Negate previous condition
bool prev_value = _conditionalStatements.top();
_conditionalStatements.pop();
_conditionalStatements.push(!prev_value);
}
else
{
LogError(ErrorCode::ElseIfWithoutIf);
}
}
else if (directive == "endif")
{
if (!_conditionalStatements.empty())
{
_conditionalStatements.pop_back();
_conditionalStatements.pop();
}
else
{
Expand Down
4 changes: 3 additions & 1 deletion Compiler/preproc/preprocessor.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <stack>
#include "script/cs_parser_common.h"
#include "script/cc_macrotable.h"
#include "util/string.h"
Expand All @@ -17,6 +18,7 @@ namespace Preprocessor {
UserDefinedError,
EndIfWithoutIf,
IfWithoutEndIf,
ElseIfWithoutIf,
InvalidVersionNumber,
UnterminatedString
};
Expand All @@ -28,7 +30,7 @@ namespace Preprocessor {
int _lineNumber;
String _scriptName;
Version _applicationVersion;
std::vector<bool> _conditionalStatements = std::vector<bool>();
std::stack<bool> _conditionalStatements;

static void LogError(ErrorCode error, const String &message = nullptr);

Expand Down
77 changes: 77 additions & 0 deletions Compiler/test/preprocessor_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,68 @@ Display("This does");
}


TEST(Preprocess, IfDefElse) {
Preprocessor pp = Preprocessor();
const char* inpl = R"EOS(
#define FOO
#ifdef FOO
Display("This displays!");
#else
Display("This doesn't");
#endif
#ifndef FOO
Display("This doesn't");
#else
Display("This displays!");
#endif
#undef FOO
#ifdef FOO
Display("This doesn't");
#else
Display("This displays!");
#endif
#ifndef FOO
Display("This displays!");
#else
Display("This doesn't");
#endif
)EOS";

clear_error();
String res = pp.Preprocess(inpl, "ScriptIfDefElse");

EXPECT_STREQ(last_seen_cc_error(), "");

std::vector<AGSString> lines = SplitLines(res);
ASSERT_EQ(lines.size(), 25);

ASSERT_STREQ(lines[0].GetCStr(), "\"__NEWSCRIPTSTART_ScriptIfDefElse\"");
ASSERT_STREQ(lines[1].GetCStr(), "");
ASSERT_STREQ(lines[2].GetCStr(), "");
ASSERT_STREQ(lines[3].GetCStr(), "");
ASSERT_STREQ(lines[4].GetCStr(), "Display(\"This displays!\");");
ASSERT_STREQ(lines[5].GetCStr(), "");
ASSERT_STREQ(lines[6].GetCStr(), "");
ASSERT_STREQ(lines[7].GetCStr(), "");
ASSERT_STREQ(lines[8].GetCStr(), "");
ASSERT_STREQ(lines[9].GetCStr(), "");
ASSERT_STREQ(lines[10].GetCStr(), "");
ASSERT_STREQ(lines[11].GetCStr(), "Display(\"This displays!\");");
ASSERT_STREQ(lines[12].GetCStr(), "");
ASSERT_STREQ(lines[13].GetCStr(), "");
ASSERT_STREQ(lines[14].GetCStr(), "");
ASSERT_STREQ(lines[15].GetCStr(), "");
ASSERT_STREQ(lines[16].GetCStr(), "");
ASSERT_STREQ(lines[17].GetCStr(), "Display(\"This displays!\");");
ASSERT_STREQ(lines[18].GetCStr(), "");
ASSERT_STREQ(lines[19].GetCStr(), "");
ASSERT_STREQ(lines[20].GetCStr(), "Display(\"This displays!\");");
ASSERT_STREQ(lines[21].GetCStr(), "");
ASSERT_STREQ(lines[22].GetCStr(), "");
ASSERT_STREQ(lines[23].GetCStr(), "");
}


TEST(Preprocess, IfVer) {
Preprocessor pp = Preprocessor();
pp.SetAppVersion("3.6.0.5");
Expand Down Expand Up @@ -390,6 +452,21 @@ Display("test");
EXPECT_STREQ(last_seen_cc_error(), "#endif has no matching #if");
}

TEST(Preprocess, ElseWithoutIf) {
Preprocessor pp = Preprocessor();
const char* inpl = R"EOS(
#ifdef BAR
#endif
Display("test");
#else
)EOS";

clear_error();
String res = pp.Preprocess(inpl, "ElseWithoutIf");

EXPECT_STREQ(last_seen_cc_error(), "#else has no matching #if");
}


} // Preprocessor
} // AGS
1 change: 1 addition & 0 deletions Editor/AGS.CScript.Compiler/Entities/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public enum ErrorCode
UserDefinedError,
EndIfWithoutIf,
IfWithoutEndIf,
ElseWithoutIf,
InvalidVersionNumber,
UnexpectedToken = 100,
InvalidUseOfKeyword,
Expand Down
12 changes: 12 additions & 0 deletions Editor/AGS.CScript.Compiler/Preprocessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,18 @@ private string PreProcessDirective(string line)
{
ProcessConditionalDirective(directive, line, _results);
}
else if (directive == "else")
{
if (_conditionalStatements.Count > 0)
{
// Negate previous condition
_conditionalStatements.Push(!_conditionalStatements.Pop());
}
else
{
RecordError(ErrorCode.ElseWithoutIf, "#else has no matching #if");
}
}
else if (directive == "endif")
{
if (_conditionalStatements.Count > 0)
Expand Down
14 changes: 14 additions & 0 deletions Editor/AGS.Editor/AutoComplete.cs
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,20 @@ private static void ProcessPreProcessorDirective(List<ScriptDefine> defines, ref
state.InsideIfDefBlock = macroName;
}
}
else if (preProcessorDirective == "else")
{
// Negate previous condition
if (state.InsideIfDefBlock != null)
{
state.InsideIfNDefBlock = state.InsideIfDefBlock;
state.InsideIfDefBlock = null;
}
else if (state.InsideIfNDefBlock != null)
{
state.InsideIfDefBlock = state.InsideIfNDefBlock;
state.InsideIfNDefBlock = null;
}
}
else if (preProcessorDirective == "endif")
{
state.InsideIfNDefBlock = null;
Expand Down

0 comments on commit 1ca7622

Please sign in to comment.