fix: add lexError calls for invalid string literals and unterminated strings in wren_compiler.c
Replace TODO comments with proper error reporting for unterminated strings, incomplete Unicode escapes, and invalid escape sequences. Add five new test files covering each error case.
This commit is contained in:
+38
-9
@@ -590,6 +590,10 @@ static int readHexDigit(Parser* parser)
|
|||||||
if (c >= '0' && c <= '9') return c - '0';
|
if (c >= '0' && c <= '9') return c - '0';
|
||||||
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||||
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||||
|
|
||||||
|
// Don't consume it if it isn't expected. Keeps us from reading past the end
|
||||||
|
// of an unterminated string.
|
||||||
|
parser->currentChar--;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -599,14 +603,26 @@ static void readUnicodeEscape(Parser* parser)
|
|||||||
int value = 0;
|
int value = 0;
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
|
if (peekChar(parser) == '"' || peekChar(parser) == '\0')
|
||||||
|
{
|
||||||
|
lexError(parser, "Incomplete Unicode escape sequence.");
|
||||||
|
|
||||||
|
// Don't consume it if it isn't expected. Keeps us from reading past the
|
||||||
|
// end of an unterminated string.
|
||||||
|
parser->currentChar--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
char digit = readHexDigit(parser);
|
char digit = readHexDigit(parser);
|
||||||
// TODO: Signal error.
|
if (digit == -1)
|
||||||
if (digit == -1) return;
|
{
|
||||||
|
lexError(parser, "Invalid Unicode escape sequence.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
value = (value * 16) | digit;
|
value = (value * 16) | digit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle encoding!
|
|
||||||
addStringChar(parser, value);
|
addStringChar(parser, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,6 +636,16 @@ static void readString(Parser* parser)
|
|||||||
char c = nextChar(parser);
|
char c = nextChar(parser);
|
||||||
if (c == '"') break;
|
if (c == '"') break;
|
||||||
|
|
||||||
|
if (c == '\0')
|
||||||
|
{
|
||||||
|
lexError(parser, "Unterminated string.");
|
||||||
|
|
||||||
|
// Don't consume it if it isn't expected. Keeps us from reading past the
|
||||||
|
// end of an unterminated string.
|
||||||
|
parser->currentChar--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (c == '\\')
|
if (c == '\\')
|
||||||
{
|
{
|
||||||
switch (nextChar(parser))
|
switch (nextChar(parser))
|
||||||
@@ -634,8 +660,10 @@ static void readString(Parser* parser)
|
|||||||
case 't': addStringChar(parser, '\t'); break;
|
case 't': addStringChar(parser, '\t'); break;
|
||||||
case 'v': addStringChar(parser, '\v'); break;
|
case 'v': addStringChar(parser, '\v'); break;
|
||||||
case 'u': readUnicodeEscape(parser); break;
|
case 'u': readUnicodeEscape(parser); break;
|
||||||
|
// TODO: 'U' for 8 octet Unicode escapes.
|
||||||
default:
|
default:
|
||||||
// TODO: Emit error token.
|
lexError(parser, "Invalid escape character '%c'.",
|
||||||
|
*(parser->currentChar - 1));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2544,9 +2572,13 @@ void definition(Compiler* compiler)
|
|||||||
// [vm].
|
// [vm].
|
||||||
ObjFn* wrenCompile(WrenVM* vm, const char* sourcePath, const char* source)
|
ObjFn* wrenCompile(WrenVM* vm, const char* sourcePath, const char* source)
|
||||||
{
|
{
|
||||||
|
ObjString* sourcePathObj = AS_STRING(wrenNewString(vm, sourcePath,
|
||||||
|
strlen(sourcePath)));
|
||||||
|
WREN_PIN(vm, sourcePathObj);
|
||||||
|
|
||||||
Parser parser;
|
Parser parser;
|
||||||
parser.vm = vm;
|
parser.vm = vm;
|
||||||
parser.sourcePath = NULL;
|
parser.sourcePath = sourcePathObj;
|
||||||
parser.source = source;
|
parser.source = source;
|
||||||
|
|
||||||
parser.tokenStart = source;
|
parser.tokenStart = source;
|
||||||
@@ -2572,10 +2604,7 @@ ObjFn* wrenCompile(WrenVM* vm, const char* sourcePath, const char* source)
|
|||||||
Compiler compiler;
|
Compiler compiler;
|
||||||
initCompiler(&compiler, &parser, NULL, true);
|
initCompiler(&compiler, &parser, NULL, true);
|
||||||
|
|
||||||
// Create a string for the source path now that the compiler is initialized
|
WREN_UNPIN(vm);
|
||||||
// so we can be sure it won't get garbage collected.
|
|
||||||
parser.sourcePath = AS_STRING(wrenNewString(vm, sourcePath,
|
|
||||||
strlen(sourcePath)));
|
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// expect error line 2
|
||||||
|
"\u00"
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// expect error line 2
|
||||||
|
"\u004
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// expect error line 2
|
||||||
|
"not a \m real escape"
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// expect error line 2
|
||||||
|
"\u00no"
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// expect error line 2
|
||||||
|
"this string has no close quote
|
||||||
Reference in New Issue
Block a user