Updated to test lexical errors
This commit is contained in:
parent
3aa4af6577
commit
6aad733263
|
|
@ -103,6 +103,11 @@ typedef struct {
|
||||||
TestIdentifierValue *output_values;
|
TestIdentifierValue *output_values;
|
||||||
} TestTypeTupleValue;
|
} TestTypeTupleValue;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t length;
|
||||||
|
const char *message;
|
||||||
|
} TestErrorMessage;
|
||||||
|
|
||||||
LexerTest start_up_test(const char *test_name, const char *test_code);
|
LexerTest start_up_test(const char *test_name, const char *test_code);
|
||||||
void clean_up_test(LexerResult result);
|
void clean_up_test(LexerResult result);
|
||||||
TestResult error_test(LexerTest *test, LexerResult result, SlsError error);
|
TestResult error_test(LexerTest *test, LexerResult result, SlsError error);
|
||||||
|
|
@ -128,5 +133,6 @@ Boolean test_array_boolean_value(LexerTest *test, LexerResult result, size_t i,
|
||||||
Boolean test_array_struct_inline_value(LexerTest *test, LexerResult result, size_t i, TestArrayStructInlineValue *values);
|
Boolean test_array_struct_inline_value(LexerTest *test, LexerResult result, size_t i, TestArrayStructInlineValue *values);
|
||||||
Boolean test_token_string_value(LexerTest *test, LexerResult result, size_t i, TestTokenStringValue *values);
|
Boolean test_token_string_value(LexerTest *test, LexerResult result, size_t i, TestTokenStringValue *values);
|
||||||
Boolean test_type_tuple_value(LexerTest *test, LexerResult result, size_t i, TestTypeTupleValue *values);
|
Boolean test_type_tuple_value(LexerTest *test, LexerResult result, size_t i, TestTypeTupleValue *values);
|
||||||
|
Boolean test_for_error(LexerTest *test, LexerResult result, size_t i, TestErrorMessage *error);
|
||||||
|
|
||||||
#endif // SLS_LEXER_TEST_HELPERS_H
|
#endif // SLS_LEXER_TEST_HELPERS_H
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,12 @@
|
||||||
extern const char *TEST_FILE_NAME;
|
extern const char *TEST_FILE_NAME;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TEST_ERROR,
|
TEST_ERROR, // The test encountered an error
|
||||||
TEST_LOGIC_FAIL,
|
TEST_LOGIC_FAIL, // The lexer encountered an error
|
||||||
TEST_ERROR_FAIL,
|
TEST_LOGIC_ERROR_FAIL, // The test failed because of a lexical error reported from the parsed code
|
||||||
TEST_PASS,
|
TEST_ERROR_FAIL, // The test failed
|
||||||
TEST_NOT_IMPLEMENTED,
|
TEST_PASS, // The test passed
|
||||||
|
TEST_NOT_IMPLEMENTED, // The test is not implemented
|
||||||
} TestResultType;
|
} TestResultType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,13 @@ TestResult logic_fail_test(LexerTest *test, LexerResult result, char *message) {
|
||||||
return test->result;
|
return test->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestResult logic_error_fail_test(LexerTest *test, LexerResult result, SlsError error) {
|
||||||
|
clean_up_test(result);
|
||||||
|
test->result.status = TEST_LOGIC_ERROR_FAIL;
|
||||||
|
test->result.error = error;
|
||||||
|
return test->result;
|
||||||
|
}
|
||||||
|
|
||||||
TestResult error_fail_test(LexerTest *test, LexerResult result, SlsError error) {
|
TestResult error_fail_test(LexerTest *test, LexerResult result, SlsError error) {
|
||||||
clean_up_test(result);
|
clean_up_test(result);
|
||||||
test->result.status = TEST_ERROR_FAIL;
|
test->result.status = TEST_ERROR_FAIL;
|
||||||
|
|
@ -245,6 +252,22 @@ static char *type_tuple_element_boolean_should_be(size_t i, size_t j, Boolean va
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *token_should_be_error(size_t i, TestErrorMessage should, TokenType found) {
|
||||||
|
size_t length = ceil(log10(i + 1)) + should.length + strnlen(TOKEN_TYPES_NAMES[found], TYPE_NAMES_SAFE_LENGTH) + 72;
|
||||||
|
char *string = (char *)malloc(sizeof(char) * length);
|
||||||
|
if (string == 0) return string;
|
||||||
|
snprintf(string, length, "Token #%zu should be an error with a message of %s, but found token of type %s", i, should.message, TOKEN_TYPES_NAMES[found]);
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *error_should_be(size_t i, TestErrorMessage should, SlsError found) {
|
||||||
|
size_t length = ceil(log10(i + 1)) + should.length + strlen(found.message) + 77;
|
||||||
|
char *string = (char *)malloc(sizeof(char) * length);
|
||||||
|
if (string == 0) return string;
|
||||||
|
snprintf(string, length, "Token #%zu should be an error with a message of %s, but found error with message %s", i, should.message, found.message);
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
// Test parts
|
// Test parts
|
||||||
|
|
||||||
static Boolean test_token_type(LexerTest *test, LexerResult result, size_t i, TokenType token_type) {
|
static Boolean test_token_type(LexerTest *test, LexerResult result, size_t i, TokenType token_type) {
|
||||||
|
|
@ -253,7 +276,7 @@ static Boolean test_token_type(LexerTest *test, LexerResult result, size_t i, To
|
||||||
logic_fail_test(test, result, unexpected_end_of_token_stream(i + 1));
|
logic_fail_test(test, result, unexpected_end_of_token_stream(i + 1));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} if (head->type == SLS_ERROR) {
|
} if (head->type == SLS_ERROR) {
|
||||||
error_fail_test(test, result, head->error);
|
logic_error_fail_test(test, result, head->error);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} if (head->result.type != token_type) {
|
} if (head->result.type != token_type) {
|
||||||
logic_fail_test(test, result, token_should_be(i + 1, token_type, head->result.type));
|
logic_fail_test(test, result, token_should_be(i + 1, token_type, head->result.type));
|
||||||
|
|
@ -576,3 +599,15 @@ Boolean test_type_tuple_value(LexerTest *test, LexerResult result, size_t i, Tes
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Boolean test_for_error(LexerTest *test, LexerResult result, size_t i, TestErrorMessage *error) {
|
||||||
|
LexerTokenResult *head = get_token(result.result, i);
|
||||||
|
if (head->type != SLS_ERROR) {
|
||||||
|
logic_fail_test(test, result, token_should_be_error(i + 1, *error, head->result.type));
|
||||||
|
return TRUE;
|
||||||
|
} if (strncmp(head->error.message, error->message, error->length+1) != 0) {
|
||||||
|
logic_fail_test(test, result, error_should_be(i + 1, *error, head->error));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@
|
||||||
#include "tests/tests.h"
|
#include "tests/tests.h"
|
||||||
|
|
||||||
|
|
||||||
static const size_t NUM_OF_TESTS = 14;
|
static const size_t NUM_OF_TESTS = 22;
|
||||||
|
|
||||||
static TestResult test_Empty_Statement() {
|
static TestResult test_Empty_Statement() {
|
||||||
LexerTest test = start_up_test("test_Empty_Statement", "");
|
LexerTest test = start_up_test("test_Empty_Statement", "");
|
||||||
LexerResult result = lexical_analysis(&test.lexer_info);
|
LexerResult result = lexical_analysis(&test.lexer_info);
|
||||||
|
|
@ -111,7 +112,7 @@ static TestResult test_Integer_i8_Decimal_127() {
|
||||||
LexerResult result = lexical_analysis(&test.lexer_info);
|
LexerResult result = lexical_analysis(&test.lexer_info);
|
||||||
if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);
|
if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
// Unhandled token type: i8
|
if (test_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I8, 127})) return test.result;
|
||||||
if (test_eof_value(&test, result, i++, 0)) return test.result;
|
if (test_eof_value(&test, result, i++, 0)) return test.result;
|
||||||
return pass_test(&test, result);
|
return pass_test(&test, result);
|
||||||
}
|
}
|
||||||
|
|
@ -121,7 +122,7 @@ static TestResult test_Integer_i8_Decimal_128() {
|
||||||
LexerResult result = lexical_analysis(&test.lexer_info);
|
LexerResult result = lexical_analysis(&test.lexer_info);
|
||||||
if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);
|
if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
// Unhandled token type: i8
|
if (test_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I8, -128})) return test.result;
|
||||||
if (test_eof_value(&test, result, i++, 0)) return test.result;
|
if (test_eof_value(&test, result, i++, 0)) return test.result;
|
||||||
return pass_test(&test, result);
|
return pass_test(&test, result);
|
||||||
}
|
}
|
||||||
|
|
@ -131,7 +132,7 @@ static TestResult test_Integer_u8_Decimal_255() {
|
||||||
LexerResult result = lexical_analysis(&test.lexer_info);
|
LexerResult result = lexical_analysis(&test.lexer_info);
|
||||||
if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);
|
if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
// Unhandled token type: u8
|
if (test_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_U8, 255})) return test.result;
|
||||||
if (test_eof_value(&test, result, i++, 0)) return test.result;
|
if (test_eof_value(&test, result, i++, 0)) return test.result;
|
||||||
return pass_test(&test, result);
|
return pass_test(&test, result);
|
||||||
}
|
}
|
||||||
|
|
@ -146,6 +147,42 @@ static TestResult test_Integer_Default_Decimal_with_Underscore() {
|
||||||
return pass_test(&test, result);
|
return pass_test(&test, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TestResult test_Integer_Default_Decimal_with_Commas_Invalid() {
|
||||||
|
LexerTest test = start_up_test("test_Integer_Default_Decimal_with_Commas_Invalid", "1,000,000");
|
||||||
|
LexerResult result = lexical_analysis(&test.lexer_info);
|
||||||
|
if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);
|
||||||
|
size_t i = 0;
|
||||||
|
if (test_for_error(&test, result, i++, &(TestErrorMessage){52, "Invalid numeric literal: unexpected ',' in integer."})) return test.result;
|
||||||
|
return pass_test(&test, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static TestResult test_Integer_i8_Overflow() {
|
||||||
|
LexerTest test = start_up_test("test_Integer_i8_Overflow", "128i8");
|
||||||
|
LexerResult result = lexical_analysis(&test.lexer_info);
|
||||||
|
if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);
|
||||||
|
size_t i = 0;
|
||||||
|
if (test_eof_value(&test, result, i++, 0)) return test.result;
|
||||||
|
return pass_test(&test, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static TestResult test_Integer_i8_Underflow() {
|
||||||
|
LexerTest test = start_up_test("test_Integer_i8_Underflow", "-129i8");
|
||||||
|
LexerResult result = lexical_analysis(&test.lexer_info);
|
||||||
|
if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);
|
||||||
|
size_t i = 0;
|
||||||
|
if (test_eof_value(&test, result, i++, 0)) return test.result;
|
||||||
|
return pass_test(&test, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static TestResult test_Integer_Default_Invalid_Characters() {
|
||||||
|
LexerTest test = start_up_test("test_Integer_Default_Invalid_Characters", "12a3");
|
||||||
|
LexerResult result = lexical_analysis(&test.lexer_info);
|
||||||
|
if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);
|
||||||
|
size_t i = 0;
|
||||||
|
if (test_for_error(&test, result, i++, &(TestErrorMessage){51, "Invalid numeric literal: unexpected character 'a'."})) return test.result;
|
||||||
|
return pass_test(&test, result);
|
||||||
|
}
|
||||||
|
|
||||||
static TestResult test_Integer_Default_Whitespace() {
|
static TestResult test_Integer_Default_Whitespace() {
|
||||||
LexerTest test = start_up_test("test_Integer_Default_Whitespace", " 42 ");
|
LexerTest test = start_up_test("test_Integer_Default_Whitespace", " 42 ");
|
||||||
LexerResult result = lexical_analysis(&test.lexer_info);
|
LexerResult result = lexical_analysis(&test.lexer_info);
|
||||||
|
|
@ -156,6 +193,42 @@ static TestResult test_Integer_Default_Whitespace() {
|
||||||
return pass_test(&test, result);
|
return pass_test(&test, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TestResult test_Integer_Default_Invalid_Prefix() {
|
||||||
|
LexerTest test = start_up_test("test_Integer_Default_Invalid_Prefix", "0b2");
|
||||||
|
LexerResult result = lexical_analysis(&test.lexer_info);
|
||||||
|
if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);
|
||||||
|
size_t i = 0;
|
||||||
|
if (test_for_error(&test, result, i++, &(TestErrorMessage){47, "Invalid binary literal: digit '2' not allowed."})) return test.result;
|
||||||
|
return pass_test(&test, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static TestResult test_Integer_Default_Invalid_Underscore_Start() {
|
||||||
|
LexerTest test = start_up_test("test_Integer_Default_Invalid_Underscore_Start", "_42");
|
||||||
|
LexerResult result = lexical_analysis(&test.lexer_info);
|
||||||
|
if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);
|
||||||
|
size_t i = 0;
|
||||||
|
if (test_for_error(&test, result, i++, &(TestErrorMessage){55, "Invalid numeric literal: cannot start with underscore."})) return test.result;
|
||||||
|
return pass_test(&test, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static TestResult test_Integer_Default_Invalid_Underscore_End() {
|
||||||
|
LexerTest test = start_up_test("test_Integer_Default_Invalid_Underscore_End", "42_");
|
||||||
|
LexerResult result = lexical_analysis(&test.lexer_info);
|
||||||
|
if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);
|
||||||
|
size_t i = 0;
|
||||||
|
if (test_for_error(&test, result, i++, &(TestErrorMessage){53, "Invalid numeric literal: cannot end with underscore."})) return test.result;
|
||||||
|
return pass_test(&test, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static TestResult test_Integer_Default_Invalid_Underscore_Double() {
|
||||||
|
LexerTest test = start_up_test("test_Integer_Default_Invalid_Underscore_Double", "4__2");
|
||||||
|
LexerResult result = lexical_analysis(&test.lexer_info);
|
||||||
|
if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);
|
||||||
|
size_t i = 0;
|
||||||
|
if (test_for_error(&test, result, i++, &(TestErrorMessage){62, "Invalid numeric literal: consecutive underscores not allowed."})) return test.result;
|
||||||
|
return pass_test(&test, result);
|
||||||
|
}
|
||||||
|
|
||||||
TestsReport run_lexer_tests() {
|
TestsReport run_lexer_tests() {
|
||||||
TestsReport test_report = (TestsReport) {
|
TestsReport test_report = (TestsReport) {
|
||||||
.section = "lexer_tests",
|
.section = "lexer_tests",
|
||||||
|
|
@ -178,7 +251,15 @@ TestsReport run_lexer_tests() {
|
||||||
test_report.tests[i++] = test_Integer_i8_Decimal_128();
|
test_report.tests[i++] = test_Integer_i8_Decimal_128();
|
||||||
test_report.tests[i++] = test_Integer_u8_Decimal_255();
|
test_report.tests[i++] = test_Integer_u8_Decimal_255();
|
||||||
test_report.tests[i++] = test_Integer_Default_Decimal_with_Underscore();
|
test_report.tests[i++] = test_Integer_Default_Decimal_with_Underscore();
|
||||||
|
test_report.tests[i++] = test_Integer_Default_Decimal_with_Commas_Invalid();
|
||||||
|
test_report.tests[i++] = test_Integer_i8_Overflow();
|
||||||
|
test_report.tests[i++] = test_Integer_i8_Underflow();
|
||||||
|
test_report.tests[i++] = test_Integer_Default_Invalid_Characters();
|
||||||
test_report.tests[i++] = test_Integer_Default_Whitespace();
|
test_report.tests[i++] = test_Integer_Default_Whitespace();
|
||||||
|
test_report.tests[i++] = test_Integer_Default_Invalid_Prefix();
|
||||||
|
test_report.tests[i++] = test_Integer_Default_Invalid_Underscore_Start();
|
||||||
|
test_report.tests[i++] = test_Integer_Default_Invalid_Underscore_End();
|
||||||
|
test_report.tests[i++] = test_Integer_Default_Invalid_Underscore_Double();
|
||||||
|
|
||||||
return test_report;
|
return test_report;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,12 @@ int main(void) {
|
||||||
break;
|
break;
|
||||||
case TEST_ERROR_FAIL:
|
case TEST_ERROR_FAIL:
|
||||||
// Magenta
|
// Magenta
|
||||||
printf("\x1b[35mTest failed (errored): %s\n\t%s\n\x1b[0m", lexer_reports.tests[i].name, lexer_reports.tests[i].error.message);
|
printf("\x1b[35mLexing errored: %s\n\t%s\n\x1b[0m", lexer_reports.tests[i].name, lexer_reports.tests[i].error.message);
|
||||||
|
break;
|
||||||
|
case TEST_LOGIC_ERROR_FAIL:
|
||||||
|
// Red
|
||||||
|
printf("\x1b[31mTest failed with error: %s\n\t%s\n\x1b[0m", lexer_reports.tests[i].name, lexer_reports.tests[i].error.message);
|
||||||
|
free(lexer_reports.tests[i].message);
|
||||||
break;
|
break;
|
||||||
case TEST_LOGIC_FAIL:
|
case TEST_LOGIC_FAIL:
|
||||||
// Red
|
// Red
|
||||||
|
|
@ -37,6 +42,10 @@ int main(void) {
|
||||||
// Blue
|
// Blue
|
||||||
printf("\x1b[34mTest not implemented: %s\n\x1b[0m", lexer_reports.tests[i].name);
|
printf("\x1b[34mTest not implemented: %s\n\x1b[0m", lexer_reports.tests[i].name);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
// Bright Red
|
||||||
|
printf("\x1b[91mTest errored: %s\n\tUnknown test result status.\n\x1b[0m", lexer_reports.tests[i].name);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,9 @@
|
||||||
# tokens:
|
# tokens:
|
||||||
# - type: Token Type
|
# - type: Token Type
|
||||||
# value: Token Value
|
# value: Token Value
|
||||||
# lexer_error:
|
|
||||||
# message: Error message.
|
|
||||||
# # Parsed operations or parsing error (if no lexer error)
|
# # Parsed operations or parsing error (if no lexer error)
|
||||||
# operations:
|
# operations:
|
||||||
# - function: Operation Name
|
# - function: Operation Name
|
||||||
# parsing_error:
|
|
||||||
# message: Error message.
|
|
||||||
# # Final stack state and/or runtime error (if no lexer or parsing error)
|
# # Final stack state and/or runtime error (if no lexer or parsing error)
|
||||||
# stack_final:
|
# stack_final:
|
||||||
# - type: Stack Item Type
|
# - type: Stack Item Type
|
||||||
|
|
@ -190,8 +186,9 @@
|
||||||
|
|
||||||
- name: Integer Default Decimal with Commas Invalid
|
- name: Integer Default Decimal with Commas Invalid
|
||||||
code: "1,000,000"
|
code: "1,000,000"
|
||||||
lexer_error:
|
tokens:
|
||||||
message: "Invalid numeric literal: unexpected ',' in integer."
|
- type: error
|
||||||
|
value: "Invalid numeric literal: unexpected ',' in integer."
|
||||||
|
|
||||||
- name: Integer i8 Overflow
|
- name: Integer i8 Overflow
|
||||||
code: "128i8"
|
code: "128i8"
|
||||||
|
|
@ -205,8 +202,9 @@
|
||||||
|
|
||||||
- name: Integer Default Invalid Characters
|
- name: Integer Default Invalid Characters
|
||||||
code: "12a3"
|
code: "12a3"
|
||||||
lexer_error:
|
tokens:
|
||||||
message: "Invalid numeric literal: unexpected character 'a'."
|
- type: error
|
||||||
|
value: "Invalid numeric literal: unexpected character 'a'."
|
||||||
|
|
||||||
- name: Integer Default Whitespace
|
- name: Integer Default Whitespace
|
||||||
code: " 42 "
|
code: " 42 "
|
||||||
|
|
@ -223,23 +221,27 @@
|
||||||
|
|
||||||
- name: Integer Default Invalid Prefix
|
- name: Integer Default Invalid Prefix
|
||||||
code: "0b2"
|
code: "0b2"
|
||||||
lexer_error:
|
tokens:
|
||||||
message: "Invalid binary literal: digit '2' not allowed."
|
- type: error
|
||||||
|
value: "Invalid binary literal: digit '2' not allowed."
|
||||||
|
|
||||||
- name: Integer Default Invalid Underscore Start
|
- name: Integer Default Invalid Underscore Start
|
||||||
code: "_42"
|
code: "_42"
|
||||||
lexer_error:
|
tokens:
|
||||||
message: "Invalid numeric literal: cannot start with underscore."
|
- type: error
|
||||||
|
value: "Invalid numeric literal: cannot start with underscore."
|
||||||
|
|
||||||
- name: Integer Default Invalid Underscore End
|
- name: Integer Default Invalid Underscore End
|
||||||
code: "42_"
|
code: "42_"
|
||||||
lexer_error:
|
tokens:
|
||||||
message: "Invalid numeric literal: cannot end with underscore."
|
- type: error
|
||||||
|
value: "Invalid numeric literal: cannot end with underscore."
|
||||||
|
|
||||||
- name: Integer Default Invalid Underscore Double
|
- name: Integer Default Invalid Underscore Double
|
||||||
code: "4__2"
|
code: "4__2"
|
||||||
lexer_error:
|
tokens:
|
||||||
message: "Invalid numeric literal: consecutive underscores not allowed."
|
- type: error
|
||||||
|
value: "Invalid numeric literal: consecutive underscores not allowed."
|
||||||
|
|
||||||
# Basic Floats
|
# Basic Floats
|
||||||
# Basic Strings
|
# Basic Strings
|
||||||
|
|
|
||||||
|
|
@ -47,19 +47,39 @@ def c_string_literal(s: str) -> str:
|
||||||
"""Escape quotes for embedding in C string literals."""
|
"""Escape quotes for embedding in C string literals."""
|
||||||
return s.replace('"', '\\"')
|
return s.replace('"', '\\"')
|
||||||
|
|
||||||
def token_to_c_call(token: dict, idx_var="i") -> str:
|
def _token_to_c_call(token: dict, idx_var="i") -> str:
|
||||||
"""Generate a C 'test_*_value' call based on token type."""
|
"""Generate a C 'test_*_value' call based on token type."""
|
||||||
ttype = token.get("type")
|
ttype = token.get("type")
|
||||||
value = token.get("value")
|
value = token.get("value")
|
||||||
|
|
||||||
if ttype == "i64":
|
if ttype == "i64":
|
||||||
return f'if (test_integer_value(&test, result, {idx_var}++, &(TestIntegerValue){{INTEGER_I64, {value}}})) return test.result;'
|
return f'test_integer_value(&test, result, {idx_var}++, &(TestIntegerValue){{INTEGER_I64, {value}}})'
|
||||||
|
elif ttype == "i32":
|
||||||
|
return f'test_integer_value(&test, result, {idx_var}++, &(TestIntegerValue){{INTEGER_I32, {value}}})'
|
||||||
|
elif ttype == "i16":
|
||||||
|
return f'test_integer_value(&test, result, {idx_var}++, &(TestIntegerValue){{INTEGER_I16, {value}}})'
|
||||||
|
elif ttype == "i8":
|
||||||
|
return f'test_integer_value(&test, result, {idx_var}++, &(TestIntegerValue){{INTEGER_I8, {value}}})'
|
||||||
|
elif ttype == "u64":
|
||||||
|
return f'test_integer_value(&test, result, {idx_var}++, &(TestIntegerValue){{INTEGER_U64, {value}}})'
|
||||||
|
elif ttype == "u32":
|
||||||
|
return f'test_integer_value(&test, result, {idx_var}++, &(TestIntegerValue){{INTEGER_U32, {value}}})'
|
||||||
|
elif ttype == "u16":
|
||||||
|
return f'test_integer_value(&test, result, {idx_var}++, &(TestIntegerValue){{INTEGER_U16, {value}}})'
|
||||||
|
elif ttype == "u8":
|
||||||
|
return f'test_integer_value(&test, result, {idx_var}++, &(TestIntegerValue){{INTEGER_U8, {value}}})'
|
||||||
elif ttype == "identifier":
|
elif ttype == "identifier":
|
||||||
return f'if (test_identifier_value(&test, result, {idx_var}++, &(TestIdentifierValue){{FALSE, {len(value)}, "{value}"}})) return test.result;' # type: ignore
|
return f'test_identifier_value(&test, result, {idx_var}++, &(TestIdentifierValue){{FALSE, {len(value)}, "{value}"}})' # type: ignore
|
||||||
elif ttype == "identifier_literal":
|
elif ttype == "identifier_literal":
|
||||||
return f'if (test_identifier_value(&test, result, {idx_var}++, &(TestIdentifierValue){{TRUE, {len(value)}, "{value}"}})) return test.result;' # type: ignore
|
return f'test_identifier_value(&test, result, {idx_var}++, &(TestIdentifierValue){{TRUE, {len(value)}, "{value}"}})' # type: ignore
|
||||||
|
elif ttype == "error":
|
||||||
|
return f'test_for_error(&test, result, i++, &(TestErrorMessage){{{len(value)+1}, "{c_string_literal(value)}"}})' # type: ignore
|
||||||
else:
|
else:
|
||||||
return f'// Unhandled token type: {ttype}'
|
raise ValueError(f' Unhandled token type: {ttype}')
|
||||||
|
|
||||||
|
def token_to_c_call(token: dict, idx_var="i") -> str:
|
||||||
|
"""Generate a C 'test_*_value' call based on token type."""
|
||||||
|
return f"if ({_token_to_c_call(token, idx_var)}) return test.result;"
|
||||||
|
|
||||||
def generate_c_test(test: dict) -> str:
|
def generate_c_test(test: dict) -> str:
|
||||||
"""Convert a single YAML test entry to a C test function."""
|
"""Convert a single YAML test entry to a C test function."""
|
||||||
|
|
@ -68,7 +88,7 @@ def generate_c_test(test: dict) -> str:
|
||||||
tokens = test.get("tokens", [])
|
tokens = test.get("tokens", [])
|
||||||
|
|
||||||
# Function header
|
# Function header
|
||||||
c_code = [f"static TestResult {name}() " "{",
|
c_code = [f"static TestResult {name}() {{",
|
||||||
f' LexerTest test = start_up_test("{name}", "{code}");',
|
f' LexerTest test = start_up_test("{name}", "{code}");',
|
||||||
" LexerResult result = lexical_analysis(&test.lexer_info);",
|
" LexerResult result = lexical_analysis(&test.lexer_info);",
|
||||||
" if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);",
|
" if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);",
|
||||||
|
|
@ -79,7 +99,8 @@ def generate_c_test(test: dict) -> str:
|
||||||
c_code.append(" " + token_to_c_call(token))
|
c_code.append(" " + token_to_c_call(token))
|
||||||
|
|
||||||
# EOF check and return
|
# EOF check and return
|
||||||
c_code.append(" if (test_eof_value(&test, result, i++, 0)) return test.result;")
|
if 'error' not in [token.get("type") for token in tokens]:
|
||||||
|
c_code.append(" if (test_eof_value(&test, result, i++, 0)) return test.result;")
|
||||||
c_code.append(" return pass_test(&test, result);")
|
c_code.append(" return pass_test(&test, result);")
|
||||||
c_code.append("}\n")
|
c_code.append("}\n")
|
||||||
|
|
||||||
|
|
@ -100,7 +121,7 @@ def yaml_to_c_tests(yaml_path: str, output_path: str):
|
||||||
|
|
||||||
program = [
|
program = [
|
||||||
file_headers,
|
file_headers,
|
||||||
f"static const size_t NUM_OF_TESTS = {len(tests)};",
|
f"static const size_t NUM_OF_TESTS = {len(tests)};\n",
|
||||||
"\n".join(c_tests),
|
"\n".join(c_tests),
|
||||||
main_header,
|
main_header,
|
||||||
] + [f" test_report.tests[i++] = {sanitize_name(test['name'])}();" for test in tests]
|
] + [f" test_report.tests[i++] = {sanitize_name(test['name'])}();" for test in tests]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue