Skip to content

Commit

Permalink
[pre] Fix "Unterminated string literal" for interpolated strings skip…
Browse files Browse the repository at this point in the history
…ped in conditional compilation.

Fix #162
  • Loading branch information
pfusik committed May 11, 2024
1 parent 3aecf51 commit feefdcf
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 24 deletions.
26 changes: 20 additions & 6 deletions Lexer.fu
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ public abstract class FuLexer
protected string() StringValue; // for FuToken.LiteralString, FuToken.InterpolatedString, FuToken.Id
HashSet<string()>() PreSymbols;
bool LineMode = false;
bool EnableDocComments = true;
bool SkippingUnmet = false;
protected bool ParsingTypeArg = false;
Stack<bool>() PreElseStack;

Expand Down Expand Up @@ -453,7 +453,7 @@ public abstract class FuLexer

protected FuToken ReadString!(bool interpolated)
{
for (int offset = this.CharOffset; ; ReadCharLiteral()) {
for (int offset = this.CharOffset;;) {
switch (PeekChar()) {
case -1:
ReportError("Unterminated string literal");
Expand All @@ -473,13 +473,27 @@ public abstract class FuLexer
if (interpolated) {
int endOffset = this.CharOffset;
ReadChar();
if (PeekChar() != '{') {
if (EatChar('{'))
break;
if (!this.SkippingUnmet) {
this.StringValue = Encoding.UTF8.GetString(this.Input, offset, endOffset - offset);
return FuToken.InterpolatedString;
}
for (;;) {
FuToken token = ReadPreToken();
if (token == FuToken.RightBrace)
break;
if (token == FuToken.EndOfFile) {
ReportError("Unterminated string literal");
return FuToken.EndOfFile;
}
}
}
else
ReadChar();
break;
default:
ReadCharLiteral();
break;
}
}
Expand Down Expand Up @@ -565,7 +579,7 @@ public abstract class FuLexer
case '/':
if (EatChar('/')) {
c = ReadChar();
if (c == '/' && this.EnableDocComments) {
if (c == '/' && !this.SkippingUnmet) {
SkipWhitespace();
switch (PeekChar()) {
case '\n':
Expand Down Expand Up @@ -946,7 +960,7 @@ public abstract class FuLexer

void SkipUnmet!(FuPreState state)
{
this.EnableDocComments = false;
this.SkippingUnmet = true;
for (;;) {
// state == FuPreState.NotYet: we are in a conditional that wasn't met yet
// else: we are in a conditional that was met before
Expand Down Expand Up @@ -989,7 +1003,7 @@ public abstract class FuLexer
{
for (;;) {
// we are in no conditionals or in all met
this.EnableDocComments = true;
this.SkippingUnmet = false;
FuToken token = ReadPreToken();
bool matched;
switch (token) {
Expand Down
24 changes: 19 additions & 5 deletions libfut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ int FuLexer::readCharLiteral()

FuToken FuLexer::readString(bool interpolated)
{
for (int offset = this->charOffset;; readCharLiteral()) {
for (int offset = this->charOffset;;) {
switch (peekChar()) {
case -1:
reportError("Unterminated string literal");
Expand All @@ -353,13 +353,27 @@ FuToken FuLexer::readString(bool interpolated)
if (interpolated) {
int endOffset = this->charOffset;
readChar();
if (peekChar() != '{') {
if (eatChar('{'))
break;
if (!this->skippingUnmet) {
this->stringValue = std::string_view(reinterpret_cast<const char *>(this->input + offset), endOffset - offset);
return FuToken::interpolatedString;
}
for (;;) {
FuToken token = readPreToken();
if (token == FuToken::rightBrace)
break;
if (token == FuToken::endOfFile) {
reportError("Unterminated string literal");
return FuToken::endOfFile;
}
}
}
else
readChar();
break;
default:
readCharLiteral();
break;
}
}
Expand Down Expand Up @@ -468,7 +482,7 @@ FuToken FuLexer::readPreToken()
case '/':
if (eatChar('/')) {
c = readChar();
if (c == '/' && this->enableDocComments) {
if (c == '/' && !this->skippingUnmet) {
skipWhitespace();
switch (peekChar()) {
case '\n':
Expand Down Expand Up @@ -1004,7 +1018,7 @@ bool FuLexer::popPreElse(std::string_view directive)

void FuLexer::skipUnmet(FuPreState state)
{
this->enableDocComments = false;
this->skippingUnmet = true;
for (;;) {
switch (readPreToken()) {
case FuToken::endOfFile:
Expand Down Expand Up @@ -1044,7 +1058,7 @@ void FuLexer::skipUnmet(FuPreState state)
FuToken FuLexer::readToken()
{
for (;;) {
this->enableDocComments = true;
this->skippingUnmet = false;
FuToken token = readPreToken();
bool matched;
switch (token) {
Expand Down
26 changes: 20 additions & 6 deletions libfut.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public abstract class FuLexer

bool LineMode = false;

bool EnableDocComments = true;
bool SkippingUnmet = false;

protected bool ParsingTypeArg = false;

Expand Down Expand Up @@ -466,7 +466,7 @@ int ReadCharLiteral()

protected FuToken ReadString(bool interpolated)
{
for (int offset = this.CharOffset;; ReadCharLiteral()) {
for (int offset = this.CharOffset;;) {
switch (PeekChar()) {
case -1:
ReportError("Unterminated string literal");
Expand All @@ -486,13 +486,27 @@ protected FuToken ReadString(bool interpolated)
if (interpolated) {
int endOffset = this.CharOffset;
ReadChar();
if (PeekChar() != '{') {
if (EatChar('{'))
break;
if (!this.SkippingUnmet) {
this.StringValue = Encoding.UTF8.GetString(this.Input, offset, endOffset - offset);
return FuToken.InterpolatedString;
}
for (;;) {
FuToken token = ReadPreToken();
if (token == FuToken.RightBrace)
break;
if (token == FuToken.EndOfFile) {
ReportError("Unterminated string literal");
return FuToken.EndOfFile;
}
}
}
else
ReadChar();
break;
default:
ReadCharLiteral();
break;
}
}
Expand Down Expand Up @@ -595,7 +609,7 @@ FuToken ReadPreToken()
case '/':
if (EatChar('/')) {
c = ReadChar();
if (c == '/' && this.EnableDocComments) {
if (c == '/' && !this.SkippingUnmet) {
SkipWhitespace();
switch (PeekChar()) {
case '\n':
Expand Down Expand Up @@ -1130,7 +1144,7 @@ bool PopPreElse(string directive)

void SkipUnmet(FuPreState state)
{
this.EnableDocComments = false;
this.SkippingUnmet = true;
for (;;) {
switch (ReadPreToken()) {
case FuToken.EndOfFile:
Expand Down Expand Up @@ -1170,7 +1184,7 @@ void SkipUnmet(FuPreState state)
FuToken ReadToken()
{
for (;;) {
this.EnableDocComments = true;
this.SkippingUnmet = false;
FuToken token = ReadPreToken();
bool matched;
switch (token) {
Expand Down
2 changes: 1 addition & 1 deletion libfut.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ class FuLexer
int nextChar;
std::unordered_set<std::string> preSymbols;
bool lineMode = false;
bool enableDocComments = true;
bool skippingUnmet = false;
std::stack<bool> preElseStack;
int readByte();
static constexpr int replacementChar = 65533;
Expand Down
26 changes: 20 additions & 6 deletions libfut.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export class FuLexer
stringValue;
#preSymbols = new Set();
#lineMode = false;
#enableDocComments = true;
#skippingUnmet = false;
parsingTypeArg = false;
#preElseStack = [];

Expand Down Expand Up @@ -444,7 +444,7 @@ export class FuLexer

readString(interpolated)
{
for (let offset = this.charOffset;; this.#readCharLiteral()) {
for (let offset = this.charOffset;;) {
switch (this.peekChar()) {
case -1:
this.reportError("Unterminated string literal");
Expand All @@ -464,13 +464,27 @@ export class FuLexer
if (interpolated) {
let endOffset = this.charOffset;
this.readChar();
if (this.peekChar() != 123) {
if (this.#eatChar(123))
break;
if (!this.#skippingUnmet) {
this.stringValue = new TextDecoder().decode(this.input.subarray(offset, offset + endOffset - offset));
return FuToken.INTERPOLATED_STRING;
}
for (;;) {
let token = this.#readPreToken();
if (token == FuToken.RIGHT_BRACE)
break;
if (token == FuToken.END_OF_FILE) {
this.reportError("Unterminated string literal");
return FuToken.END_OF_FILE;
}
}
}
else
this.readChar();
break;
default:
this.#readCharLiteral();
break;
}
}
Expand Down Expand Up @@ -579,7 +593,7 @@ export class FuLexer
case 47:
if (this.#eatChar(47)) {
c = this.readChar();
if (c == 47 && this.#enableDocComments) {
if (c == 47 && !this.#skippingUnmet) {
this.#skipWhitespace();
switch (this.peekChar()) {
case 10:
Expand Down Expand Up @@ -1119,7 +1133,7 @@ export class FuLexer

#skipUnmet(state)
{
this.#enableDocComments = false;
this.#skippingUnmet = true;
for (;;) {
switch (this.#readPreToken()) {
case FuToken.END_OF_FILE:
Expand Down Expand Up @@ -1159,7 +1173,7 @@ export class FuLexer
#readToken()
{
for (;;) {
this.#enableDocComments = true;
this.#skippingUnmet = false;
let token = this.#readPreToken();
let matched;
switch (token) {
Expand Down
11 changes: 11 additions & 0 deletions test/PreStringInterpolated.fu
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
public static class Test
{
public static bool Run()
{
#if false
int a = 0;
Console.WriteLine($"{a}");
#endif
return true;
}
}

0 comments on commit feefdcf

Please sign in to comment.