feat: add compile error detection and line tracking to test runner and compiler

Add support for testing compile errors by introducing `// expect error` annotations in test files. The test runner now validates that expected errors occur on specific lines and that the compiler exits with code 1 when errors are present. The compiler's error output is enhanced to include line numbers in the format `[Line N] Error`, and the `Token` struct gains a `line` field to track token positions. The main entry point returns exit code 1 when compilation fails, enabling the test runner to verify error exit codes.
This commit is contained in:
Bob Nystrom
2013-10-28 14:12:39 +00:00
parent cde3490579
commit b69dfe3bd6
5 changed files with 75 additions and 25 deletions
+24 -8
View File
@@ -51,8 +51,15 @@ typedef enum
typedef struct Token_s
{
TokenType type;
// The beginning of the token as an offset of characters in the source.
int start;
// The offset of the character immediately following the end of the token.
int end;
// The 1-based line where the token appears.
int line;
} Token;
typedef struct
@@ -68,6 +75,9 @@ typedef struct
// The position of the current character being lexed.
int currentChar;
// The 1-based line number of [currentChar].
int currentLine;
// The most recently lexed token.
Token current;
@@ -191,12 +201,14 @@ ObjBlock* compile(VM* vm, const char* source, size_t sourceLength)
parser.tokenStart = 0;
parser.currentChar = 0;
parser.currentLine = 1;
// Zero-init the current token. This will get copied to previous when
// advance() is called below.
parser.current.type = TOKEN_EOF;
parser.current.start = 0;
parser.current.end = 0;
parser.current.line = 0;
// Read the first token.
nextToken(&parser);
@@ -300,22 +312,22 @@ void emit(Compiler* compiler, Code code)
void error(Compiler* compiler, const char* format, ...)
{
compiler->parser->hasError = 1;
printf("Compile error on '");
fprintf(stderr, "[Line %d] Error on '", compiler->parser->previous.line);
for (int i = compiler->parser->previous.start;
i < compiler->parser->previous.end; i++)
{
putchar(compiler->parser->source[i]);
putc(compiler->parser->source[i], stderr);
}
printf("': ");
fprintf(stderr, "': ");
va_list args;
va_start(args, format);
vprintf(format, args);
vfprintf(stderr, format, args);
va_end(args);
printf("\n");
fprintf(stderr, "\n");
}
void statement(Compiler* compiler)
@@ -499,8 +511,8 @@ void primary(Compiler* compiler)
return;
}
// TODO(bob): Look for globals or names in outer scopes.
error(compiler, "Unknown variable.");
// TODO(bob): Look for names in outer scopes.
error(compiler, "Undefined variable.");
}
// Number.
@@ -734,7 +746,10 @@ void readRawToken(Parser* parser)
}
return;
case '\n': makeToken(parser, TOKEN_LINE); return;
case '\n':
parser->currentLine++;
makeToken(parser, TOKEN_LINE);
return;
case ' ': skipWhitespace(parser); break;
case '"': readString(parser); return;
@@ -842,5 +857,6 @@ void makeToken(Parser* parser, TokenType type)
parser->current.type = type;
parser->current.start = parser->tokenStart;
parser->current.end = parser->currentChar;
parser->current.line = parser->currentLine;
}
+6 -1
View File
@@ -28,15 +28,20 @@ int main(int argc, const char * argv[])
VM* vm = newVM();
ObjBlock* block = compile(vm, source, length);
int exitCode = 0;
if (block)
{
interpret(vm, block);
}
else
{
exitCode = 1;
}
freeVM(vm);
free(source);
return 0;
return exitCode;
}
/*