Skip to content

Commit ad8a914

Browse files
committed
attach token location to error tokens
Makes invalid strings error at proper location instead of at 0,0 See confusion in https://forum.dlang.org/post/mcaldhecyexsolqoctsy@forum.dlang.org
1 parent 88f247e commit ad8a914

File tree

1 file changed

+74
-16
lines changed

1 file changed

+74
-16
lines changed

src/dparse/lexer.d

Lines changed: 74 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,8 +1208,7 @@ private pure nothrow @safe:
12081208
{
12091209
if (range.index >= range.bytes.length)
12101210
{
1211-
error("Error: unterminated string literal");
1212-
token = Token(tok!"");
1211+
error(token, "Error: unterminated string literal");
12131212
return;
12141213
}
12151214
version (X86_64)
@@ -1254,8 +1253,7 @@ private pure nothrow @safe:
12541253
{
12551254
if (range.index >= range.bytes.length)
12561255
{
1257-
error("Error: unterminated string literal");
1258-
token = Token(tok!"");
1256+
error(token, "Error: unterminated string literal");
12591257
return;
12601258
}
12611259
version (X86_64)
@@ -1280,17 +1278,15 @@ private pure nothrow @safe:
12801278
range.popFront();
12811279
if (range.index >= range.bytes.length)
12821280
{
1283-
error("Error: unterminated string literal");
1284-
token = Token(tok!"");
1281+
error(token, "Error: unterminated string literal");
12851282
return;
12861283
}
12871284
range.popFront();
12881285
while (true)
12891286
{
12901287
if (range.index >= range.bytes.length)
12911288
{
1292-
error("Error: unterminated string literal");
1293-
token = Token(tok!"");
1289+
error(token, "Error: unterminated string literal");
12941290
return;
12951291
}
12961292
else if (range.bytes[range.index] == '"')
@@ -1388,8 +1384,7 @@ private pure nothrow @safe:
13881384
}
13891385
else
13901386
{
1391-
error("Error: `\"` expected to end delimited string literal");
1392-
token = Token(tok!"");
1387+
error(token, "Error: `\"` expected to end delimited string literal");
13931388
return;
13941389
}
13951390
}
@@ -1464,6 +1459,13 @@ private pure nothrow @safe:
14641459
}
14651460

14661461
advance(_front);
1462+
1463+
if (range.index >= range.bytes.length)
1464+
{
1465+
error(token, "Error: unterminated token string literal");
1466+
return;
1467+
}
1468+
14671469
while (depth > 0 && !empty)
14681470
{
14691471
auto t = front();
@@ -1503,8 +1505,7 @@ private pure nothrow @safe:
15031505
{
15041506
if (range.index >= range.bytes.length)
15051507
{
1506-
error("Error: unterminated hex string literal");
1507-
token = Token(tok!"");
1508+
error(token, "Error: unterminated hex string literal");
15081509
return;
15091510
}
15101511
else if (isWhitespace())
@@ -1520,8 +1521,7 @@ private pure nothrow @safe:
15201521
range.popFront();
15211522
break loop;
15221523
default:
1523-
error("Error: invalid character in hex string");
1524-
token = Token(tok!"");
1524+
error(token, "Error: invalid character in hex string");
15251525
return;
15261526
}
15271527
}
@@ -1706,8 +1706,7 @@ private pure nothrow @safe:
17061706
else
17071707
{
17081708
err:
1709-
error("Error: Expected `'` to end character literal");
1710-
token = Token(tok!"");
1709+
error(token, "Error: Expected `'` to end character literal");
17111710
}
17121711
}
17131712

@@ -1848,6 +1847,12 @@ private pure nothrow @safe:
18481847
auto mark = range.mark();
18491848
};
18501849

1850+
void error(ref Token token, string message)
1851+
{
1852+
token.type = tok!"";
1853+
error(message);
1854+
}
1855+
18511856
void error(string message)
18521857
{
18531858
_messages ~= Message(range.line, range.column, message, true);
@@ -2449,3 +2454,56 @@ unittest
24492454
immutable t2 = e2.tok;
24502455
immutable t3 = e3.tok;
24512456
}
2457+
2458+
/// empty '' is invalid syntax, but should still get parsed properly, with an
2459+
/// error token and proper location info
2460+
unittest
2461+
{
2462+
import std.conv : to;
2463+
import std.exception : enforce;
2464+
2465+
static immutable src = `module foo.bar;
2466+
2467+
void main() {
2468+
x = '';
2469+
}
2470+
`;
2471+
2472+
LexerConfig cf;
2473+
StringCache ca = StringCache(16);
2474+
2475+
const tokens = getTokensForParser(src, cf, &ca);
2476+
2477+
int i;
2478+
assert(tokens[i++].type == tok!"module");
2479+
assert(tokens[i++].type == tok!"identifier");
2480+
assert(tokens[i++].type == tok!".");
2481+
assert(tokens[i++].type == tok!"identifier");
2482+
assert(tokens[i++].type == tok!";");
2483+
assert(tokens[i++].type == tok!"void");
2484+
assert(tokens[i++].type == tok!"identifier");
2485+
assert(tokens[i++].type == tok!"(");
2486+
assert(tokens[i++].type == tok!")");
2487+
assert(tokens[i++].type == tok!"{");
2488+
assert(tokens[i++].type == tok!"identifier");
2489+
assert(tokens[i++].type == tok!"=");
2490+
assert(tokens[i].type == tok!"");
2491+
assert(tokens[i].line == tokens[i - 1].line);
2492+
assert(tokens[i].column == tokens[i - 1].column + 2);
2493+
i++;
2494+
assert(tokens[i++].type == tok!";");
2495+
assert(tokens[i++].type == tok!"}");
2496+
2497+
void checkInvalidTrailingString(const Token[] tokens)
2498+
{
2499+
assert(tokens.length == 3);
2500+
assert(tokens[2].index != 0);
2501+
assert(tokens[2].column >= 4);
2502+
assert(tokens[2].type == tok!"");
2503+
}
2504+
2505+
checkInvalidTrailingString(getTokensForParser(`x = "foo`, cf, &ca));
2506+
checkInvalidTrailingString(getTokensForParser(`x = r"foo`, cf, &ca));
2507+
checkInvalidTrailingString(getTokensForParser("x = `foo", cf, &ca));
2508+
checkInvalidTrailingString(getTokensForParser("x = q{foo", cf, &ca));
2509+
}

0 commit comments

Comments
 (0)