Skip to content

Commit

Permalink
Support @(XYZ) raw strings
Browse files Browse the repository at this point in the history
  • Loading branch information
ike709 committed Nov 27, 2024
1 parent 8b4e62f commit ba72e61
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 3 deletions.
70 changes: 67 additions & 3 deletions DMCompiler/Compiler/DMPreprocessor/DMPreprocessorLexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -301,20 +301,65 @@ public Token NextToken(bool ignoreWhitespace = false) {
}
case '@': { //Raw string
char delimiter = Advance();
var startLoc = CurrentLocation();

// @(XYZ) where XYZ is the delimiter
string complexDelimiter = string.Empty;
if (delimiter == '(') {
Advance();
while (GetCurrent() != ')') {
if (AtEndOfSource()) {
_compiler.Emit(WarningCode.BadExpression, startLoc,
"Unterminated string delimiter");
break;
}

complexDelimiter += GetCurrent();
Advance();
}
}

TokenTextBuilder.Clear();
TokenTextBuilder.Append('@');
TokenTextBuilder.Append(delimiter);

bool isComplex = complexDelimiter != string.Empty;
bool isLong = false;

c = Advance();
if (delimiter == '{') {
TokenTextBuilder.Append(c);

if (c == '"') isLong = true;
}

if (isLong) {
if (isComplex) {
TokenTextBuilder.Append(complexDelimiter);
TokenTextBuilder.Append(')');

// Ignore a newline immediately after @(complexDelimiter)
if (c == '\r') c = Advance();
if (c == '\n') c = Advance();

var delimIdx = 0;
do {
TokenTextBuilder.Append(c);
if (GetCurrent() == complexDelimiter[delimIdx]) delimIdx++;
if (delimIdx + 1 == complexDelimiter.Length) {
TokenTextBuilder.Remove(TokenTextBuilder.Length - delimIdx, complexDelimiter.Length - 1);
break;
}

c = Advance();
} while (!AtEndOfSource());

if (AtEndOfSource()) {
_compiler.Emit(WarningCode.BadExpression, startLoc,
"Unterminated string delimiter");
}

TokenTextBuilder.Append(complexDelimiter);
} else if (isLong) {
bool nextCharCanTerm = false;

Advance();
Expand All @@ -335,21 +380,36 @@ public Token NextToken(bool ignoreWhitespace = false) {
if (c == '"')
nextCharCanTerm = true;
} while (!AtEndOfSource());

if (AtEndOfSource()) {
_compiler.Emit(WarningCode.BadExpression, startLoc,
"Unterminated string delimiter");
}
} else {
while (c != delimiter && !AtLineEnd() && !AtEndOfSource()) {
TokenTextBuilder.Append(c);
c = Advance();
}
}

TokenTextBuilder.Append(c);
if (isComplex) Advance();
else TokenTextBuilder.Append(c);

if (!HandleLineEnd())
Advance();

string text = TokenTextBuilder.ToString();
string value;

if (isLong) {
if (isComplex) {
// Complex strings need to strip @(complexDelimiter) and a potential final newline. Newline after @(complexDelimiter) is already handled
var trimEnd = complexDelimiter.Length;
if (TokenTextBuilder[^(complexDelimiter.Length + 1)] == '\n') trimEnd += 1;
if (TokenTextBuilder[^(complexDelimiter.Length + 2)] == '\r') trimEnd += 1;
var trimStart = 3 + complexDelimiter.Length;
value = TokenTextBuilder.ToString(trimStart, TokenTextBuilder.Length - (trimStart + trimEnd));
}
else if (isLong) {
// Long strings ignore a newline immediately after the @{" and before the "}
if (TokenTextBuilder[3] == '\n')
TokenTextBuilder.Remove(3, 1);
Expand Down Expand Up @@ -639,6 +699,10 @@ private char GetCurrent() {
return _current;
}

private Location CurrentLocation() {
return new Location(File, _previousLine, _previousColumn, _isDMStandard);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private char Advance() {
int value = _source.Read();
Expand Down

0 comments on commit ba72e61

Please sign in to comment.