Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

attach token location to error tokens #483

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 81 additions & 19 deletions src/dparse/lexer.d
Original file line number Diff line number Diff line change
Expand Up @@ -1208,8 +1208,7 @@ private pure nothrow @safe:
{
if (range.index >= range.bytes.length)
{
error("Error: unterminated string literal");
token = Token(tok!"");
error(token, "Error: unterminated string literal");
return;
}
version (X86_64)
Expand Down Expand Up @@ -1254,8 +1253,7 @@ private pure nothrow @safe:
{
if (range.index >= range.bytes.length)
{
error("Error: unterminated string literal");
token = Token(tok!"");
error(token, "Error: unterminated string literal");
return;
}
version (X86_64)
Expand All @@ -1280,17 +1278,15 @@ private pure nothrow @safe:
range.popFront();
if (range.index >= range.bytes.length)
{
error("Error: unterminated string literal");
token = Token(tok!"");
error(token, "Error: unterminated string literal");
return;
}
range.popFront();
while (true)
{
if (range.index >= range.bytes.length)
{
error("Error: unterminated string literal");
token = Token(tok!"");
error(token, "Error: unterminated string literal");
return;
}
else if (range.bytes[range.index] == '"')
Expand Down Expand Up @@ -1388,8 +1384,7 @@ private pure nothrow @safe:
}
else
{
error("Error: `\"` expected to end delimited string literal");
token = Token(tok!"");
error(token, "Error: `\"` expected to end delimited string literal");
return;
}
}
Expand All @@ -1406,7 +1401,7 @@ private pure nothrow @safe:
{
Token ident;
lexIdentifier(ident);
if (isNewline())
if (!(range.index >= range.bytes.length) && isNewline())
popFrontWhitespaceAware();
else
error("Newline expected");
Expand All @@ -1431,14 +1426,15 @@ private pure nothrow @safe:
range.popFront();
}
}
IdType type;
if (!(range.index >= range.bytes.length) && range.bytes[range.index] == '"')
{
type = tok!"stringLiteral";
lexStringSuffix(type);
range.popFront();
}
else
error("`\"` expected");
IdType type = tok!"stringLiteral";
lexStringSuffix(type);
token = Token(type, cache.intern(range.slice(mark)), line, column, index);
}

Expand All @@ -1464,6 +1460,13 @@ private pure nothrow @safe:
}

advance(_front);

if (range.index >= range.bytes.length)
{
error(token, "Error: unterminated token string literal");
return;
}

while (depth > 0 && !empty)
{
auto t = front();
Expand Down Expand Up @@ -1503,8 +1506,7 @@ private pure nothrow @safe:
{
if (range.index >= range.bytes.length)
{
error("Error: unterminated hex string literal");
token = Token(tok!"");
error(token, "Error: unterminated hex string literal");
return;
}
else if (isWhitespace())
Expand All @@ -1520,8 +1522,7 @@ private pure nothrow @safe:
range.popFront();
break loop;
default:
error("Error: invalid character in hex string");
token = Token(tok!"");
error(token, "Error: invalid character in hex string");
return;
}
}
Expand Down Expand Up @@ -1706,8 +1707,7 @@ private pure nothrow @safe:
else
{
err:
error("Error: Expected `'` to end character literal");
token = Token(tok!"");
error(token, "Error: Expected `'` to end character literal");
}
}

Expand Down Expand Up @@ -1848,6 +1848,12 @@ private pure nothrow @safe:
auto mark = range.mark();
};

void error(ref Token token, string message)
{
token.type = tok!"";
error(message);
}

void error(string message)
{
_messages ~= Message(range.line, range.column, message, true);
Expand Down Expand Up @@ -2449,3 +2455,59 @@ unittest
immutable t2 = e2.tok;
immutable t3 = e3.tok;
}

/// empty '' is invalid syntax, but should still get parsed properly, with an
/// error token and proper location info
unittest
{
import std.conv : to;
import std.exception : enforce;

static immutable src = `module foo.bar;

void main() {
x = '';
}
`;

LexerConfig cf;
StringCache ca = StringCache(16);

const tokens = getTokensForParser(src, cf, &ca);

int i;
assert(tokens[i++].type == tok!"module");
assert(tokens[i++].type == tok!"identifier");
assert(tokens[i++].type == tok!".");
assert(tokens[i++].type == tok!"identifier");
assert(tokens[i++].type == tok!";");
assert(tokens[i++].type == tok!"void");
assert(tokens[i++].type == tok!"identifier");
assert(tokens[i++].type == tok!"(");
assert(tokens[i++].type == tok!")");
assert(tokens[i++].type == tok!"{");
assert(tokens[i++].type == tok!"identifier");
assert(tokens[i++].type == tok!"=");
assert(tokens[i].type == tok!"");
assert(tokens[i].line == tokens[i - 1].line);
assert(tokens[i].column == tokens[i - 1].column + 2);
i++;
assert(tokens[i++].type == tok!";");
assert(tokens[i++].type == tok!"}");

void checkInvalidTrailingString(const Token[] tokens)
{
assert(tokens.length == 3);
assert(tokens[2].index != 0);
assert(tokens[2].column >= 4);
assert(tokens[2].type == tok!"");
}

checkInvalidTrailingString(getTokensForParser(`x = "foo`, cf, &ca));
checkInvalidTrailingString(getTokensForParser(`x = r"foo`, cf, &ca));
checkInvalidTrailingString(getTokensForParser(`x = x"00`, cf, &ca));
checkInvalidTrailingString(getTokensForParser("x = `foo", cf, &ca));
checkInvalidTrailingString(getTokensForParser("x = q{foo", cf, &ca));
checkInvalidTrailingString(getTokensForParser(`x = q"foo`, cf, &ca));
checkInvalidTrailingString(getTokensForParser("x = '", cf, &ca));
}