@@ -1208,8 +1208,7 @@ private pure nothrow @safe:
1208
1208
{
1209
1209
if (range.index >= range.bytes.length)
1210
1210
{
1211
- error(" Error: unterminated string literal" );
1212
- token = Token (tok! " " );
1211
+ error(token, " Error: unterminated string literal" );
1213
1212
return ;
1214
1213
}
1215
1214
version (X86_64 )
@@ -1254,8 +1253,7 @@ private pure nothrow @safe:
1254
1253
{
1255
1254
if (range.index >= range.bytes.length)
1256
1255
{
1257
- error(" Error: unterminated string literal" );
1258
- token = Token (tok! " " );
1256
+ error(token, " Error: unterminated string literal" );
1259
1257
return ;
1260
1258
}
1261
1259
version (X86_64 )
@@ -1280,17 +1278,15 @@ private pure nothrow @safe:
1280
1278
range.popFront();
1281
1279
if (range.index >= range.bytes.length)
1282
1280
{
1283
- error(" Error: unterminated string literal" );
1284
- token = Token (tok! " " );
1281
+ error(token, " Error: unterminated string literal" );
1285
1282
return ;
1286
1283
}
1287
1284
range.popFront();
1288
1285
while (true )
1289
1286
{
1290
1287
if (range.index >= range.bytes.length)
1291
1288
{
1292
- error(" Error: unterminated string literal" );
1293
- token = Token (tok! " " );
1289
+ error(token, " Error: unterminated string literal" );
1294
1290
return ;
1295
1291
}
1296
1292
else if (range.bytes[range.index] == ' "' )
@@ -1388,8 +1384,7 @@ private pure nothrow @safe:
1388
1384
}
1389
1385
else
1390
1386
{
1391
- error(" Error: `\" ` expected to end delimited string literal" );
1392
- token = Token (tok! " " );
1387
+ error(token, " Error: `\" ` expected to end delimited string literal" );
1393
1388
return ;
1394
1389
}
1395
1390
}
@@ -1464,6 +1459,13 @@ private pure nothrow @safe:
1464
1459
}
1465
1460
1466
1461
advance(_front);
1462
+
1463
+ if (range.index >= range.bytes.length)
1464
+ {
1465
+ error(token, " Error: unterminated token string literal" );
1466
+ return ;
1467
+ }
1468
+
1467
1469
while (depth > 0 && ! empty)
1468
1470
{
1469
1471
auto t = front();
@@ -1503,8 +1505,7 @@ private pure nothrow @safe:
1503
1505
{
1504
1506
if (range.index >= range.bytes.length)
1505
1507
{
1506
- error(" Error: unterminated hex string literal" );
1507
- token = Token (tok! " " );
1508
+ error(token, " Error: unterminated hex string literal" );
1508
1509
return ;
1509
1510
}
1510
1511
else if (isWhitespace())
@@ -1520,8 +1521,7 @@ private pure nothrow @safe:
1520
1521
range.popFront();
1521
1522
break loop;
1522
1523
default :
1523
- error(" Error: invalid character in hex string" );
1524
- token = Token (tok! " " );
1524
+ error(token, " Error: invalid character in hex string" );
1525
1525
return ;
1526
1526
}
1527
1527
}
@@ -1706,8 +1706,7 @@ private pure nothrow @safe:
1706
1706
else
1707
1707
{
1708
1708
err:
1709
- error(" Error: Expected `'` to end character literal" );
1710
- token = Token (tok! " " );
1709
+ error(token, " Error: Expected `'` to end character literal" );
1711
1710
}
1712
1711
}
1713
1712
@@ -1848,6 +1847,12 @@ private pure nothrow @safe:
1848
1847
auto mark = range.mark();
1849
1848
};
1850
1849
1850
+ void error (ref Token token, string message)
1851
+ {
1852
+ token.type = tok! " " ;
1853
+ error(message);
1854
+ }
1855
+
1851
1856
void error (string message)
1852
1857
{
1853
1858
_messages ~= Message(range.line, range.column, message, true );
@@ -2449,3 +2454,56 @@ unittest
2449
2454
immutable t2 = e2.tok;
2450
2455
immutable t3 = e3.tok;
2451
2456
}
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