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
+41 -16
View File
@@ -33,6 +33,8 @@ else:
sys.exit('System not supported!')
EXPECT_PATTERN = re.compile(r'// expect: (.*)')
EXPECT_ERROR_PATTERN = re.compile(r'// expect error')
ERROR_PATTERN = re.compile(r'\[Line (\d+)\] Error ')
SKIP_PATTERN = re.compile(r'// skip: (.*)')
NONTEST_PATTERN = re.compile(r'// nontest')
@@ -112,6 +114,13 @@ def run_test(path):
if match:
expect_output.append((match.group(1), line_num))
match = EXPECT_ERROR_PATTERN.search(line)
if match:
expect_error.append(line_num)
# If we expect compile errors in the test, it should return
# exit code 1.
expect_return = 1
match = SKIP_PATTERN.search(line)
if match:
num_skipped += 1
@@ -132,10 +141,27 @@ def run_test(path):
fails = []
# Validate that no unexpected errors occurred.
if expect_return == 1 and err != '':
lines = err.split('\n')
while len(lines) > 0:
line = lines.pop(0)
match = ERROR_PATTERN.search(line)
if match:
if float(match.group(1)) not in expect_error:
fails.append('Unexpected error:')
fails.append(line)
elif line != '':
fails.append('Unexpected output on stderr:')
fails.append(line)
else:
for line in expect_error:
fails.append('Expected error on line ' + str(line) + ' and got none.')
# Validate the exit code.
if proc.returncode != 0:
fails.append('Expected return code 0 and got {0}.'.
format(proc.returncode))
if proc.returncode != expect_return:
fails.append('Expected return code {0} and got {1}.'
.format(expect_return, proc.returncode))
else:
# Validate the output.
expect_index = 0
@@ -143,23 +169,22 @@ def run_test(path):
# Remove the trailing last empty line.
out_lines = out.split('\n')
if out_lines[-1] == '':
del out_lines[-1]
del out_lines[-1]
for line in out_lines:
if expect_index >= len(expect_output):
fails.append('Got output "{0}" when none was expected.'.
format(line))
elif expect_output[expect_index][0] != line:
fails.append('Expected output "{0}" on line {1} and got "{2}".'.
format(expect_output[expect_index][0],
expect_output[expect_index][1], line))
expect_index += 1
if expect_index >= len(expect_output):
fails.append('Got output "{0}" when none was expected.'.format(line))
elif expect_output[expect_index][0] != line:
fails.append('Expected output "{0}" on line {1} and got "{2}".'.
format(expect_output[expect_index][0],
expect_output[expect_index][1], line))
expect_index += 1
while expect_index < len(expect_output):
fails.append('Missing expected output "{0}" on line {1}.'.
format(expect_output[expect_index][0],
expect_output[expect_index][1]))
expect_index += 1
fails.append('Missing expected output "{0}" on line {1}.'.
format(expect_output[expect_index][0],
expect_output[expect_index][1]))
expect_index += 1
# Display the results.
if len(fails) == 0: