From 60925dab53415713de7e30e3cf60f528763aa18b Mon Sep 17 00:00:00 2001 From: Kyler Date: Fri, 14 Nov 2025 17:22:06 -0700 Subject: [PATCH] Setting up float and character tests --- SLS_C/SlsStr.md | 1 + SLS_C/tests/lexer_test_helpers.c | 17 +++ SLS_Tests/generate_tests/char_tests.py | 158 ++++++++++++------------ SLS_Tests/generate_tests/float_tests.py | 2 +- SLS_Tests/yaml_to_c_tests.py | 6 + 5 files changed, 107 insertions(+), 77 deletions(-) diff --git a/SLS_C/SlsStr.md b/SLS_C/SlsStr.md index abc8066..ace5919 100644 --- a/SLS_C/SlsStr.md +++ b/SLS_C/SlsStr.md @@ -10,6 +10,7 @@ - `u` uint64_t - `z` size_t - `f` double +- `n` unicode uint8_t\[4\] (Not Implemented) - `s` string.h SlsStr - `t` lexer.h TokenType - `a` lexer.h ArrayType diff --git a/SLS_C/tests/lexer_test_helpers.c b/SLS_C/tests/lexer_test_helpers.c index 133a8e6..957baa9 100644 --- a/SLS_C/tests/lexer_test_helpers.c +++ b/SLS_C/tests/lexer_test_helpers.c @@ -127,6 +127,11 @@ static SlsStr integer_value_should_be(size_t i, uint64_t should, uint64_t found) return sls_format(SLS_STR("Token #%z integer value should be %i, but found %i"), i, should, found); } +static SlsStr character_value_should_be(size_t i, uint8_t should, uint8_t found) { + return sls_format(SLS_STR("Token #%z integer value should be %i, but found %i"), i, should, found); + // return sls_format(SLS_STR("Token #%z character value should be '', but found ''"), i, should[0], found[0]); +} + static SlsStr float_value_should_be(size_t i, double should, double found) { return sls_format(SLS_STR("Token #%z float value should be %f, but found %f"), i, should, found); } @@ -285,6 +290,18 @@ Boolean test_integer_value(LexerTest *test, LexerResult result, size_t i, TestIn return FALSE; } +Boolean test_character_value(LexerTest *test, LexerResult result, size_t i, uint8_t *value) { + static const TokenType token_type = TOKEN_INTEGER; + LexerTokenResult *head = get_token(result.result, i); + if (test_token_type(test, result, i, token_type)) { + return TRUE; + } if (head->result.integer_literal.value != *value) { + logic_fail_test(test, result, character_value_should_be(i + 1, *value, head->result.float_literal)); + return TRUE; + } + return FALSE; +} + Boolean test_float_value(LexerTest *test, LexerResult result, size_t i, float *value) { static const TokenType token_type = TOKEN_FLOAT; LexerTokenResult *head = get_token(result.result, i); diff --git a/SLS_Tests/generate_tests/char_tests.py b/SLS_Tests/generate_tests/char_tests.py index 8ef9043..b6e9830 100644 --- a/SLS_Tests/generate_tests/char_tests.py +++ b/SLS_Tests/generate_tests/char_tests.py @@ -5,15 +5,17 @@ from .base_tests import BaseTestGenerator class CharTestGenerator(BaseTestGenerator): """Generate test cases for character literals.""" + ENABLE_UNICODE = False + # Common escape sequences ESCAPE_SEQUENCES = { - '\\n': '\n', # Newline - '\\r': '\r', # Carriage return - '\\t': '\t', # Tab - '\\\\': '\\', # Backslash - '\\"': '"', # Double quote - "\\'": "'", # Single quote - '\\0': '\0', # Null character + ("Newline", '\\n', '\n',), # Newline + ("Carriage return", '\\r', '\r',), # Carriage return + ("Tab", '\\t', '\t',), # Tab + ("Backslash", '\\\\', '\\',), # Backslash + ("Double quote", '\\\\"', '"',), # Double quote + ("Single quote", "\\'", "'",), # Single quote + ("Null character", '\\0', '\0',), # Null character } # Hexadecimal escape examples @@ -77,8 +79,8 @@ class CharTestGenerator(BaseTestGenerator): def generate_escape_sequence_tests(self): """Generate tests for escape sequences.""" # Standard escape sequences - for escape_str, char_val in self.ESCAPE_SEQUENCES.items(): - name = f"Char Escape {escape_str}" + for escape_name, escape_str, char_val in self.ESCAPE_SEQUENCES: + name = f"Char Escape {escape_name}" code = f"'{escape_str}'" self.make_success_test(name, code, "char", char_val) @@ -88,7 +90,7 @@ class CharTestGenerator(BaseTestGenerator): ("Carriage Return", "'\\r'", '\r'), ("Tab", "'\\t'", '\t'), ("Backslash", "'\\\\'", '\\'), - ("Double Quote", "'\\\"'", '"'), + ("Double Quote", "'\\\\\"'", '"'), ("Single Quote", "'\\''", "'"), ("Null", "'\\0'", '\0'), ] @@ -163,8 +165,8 @@ class CharTestGenerator(BaseTestGenerator): self.make_success_test("Char With Leading Whitespace", " 'A'", "char", 'A') self.make_success_test("Char With Trailing Whitespace", "'A' ", "char", 'A') self.make_success_test("Char With Both Whitespace", " 'A' ", "char", 'A') - self.make_success_test("Char Tab Before", "\t'B'", "char", 'B') - self.make_success_test("Char Newline Before", "\n'C'", "char", 'C') + self.make_success_test("Char Tab Before", "\\t'B'", "char", 'B') + self.make_success_test("Char Newline Before", "\\n'C'", "char", 'C') def generate_error_tests(self): """Generate error test cases.""" @@ -185,7 +187,7 @@ class CharTestGenerator(BaseTestGenerator): # Unescaped newline self.make_error_test("Char Unescaped Newline", - "'\n'", + "'\\n'", "Invalid character literal: unescaped newline in character literal.") # Invalid escape sequence @@ -204,42 +206,43 @@ class CharTestGenerator(BaseTestGenerator): # Invalid hex digits self.make_error_test("Char Hex Invalid Digit", - "'\\xGG'", + "'\\\\xGG'", "Invalid character literal: invalid hexadecimal digit 'G'.") - # Invalid Unicode escape (no braces) - self.make_error_test("Char Unicode No Braces", - "'\\u1F600'", - "Invalid character literal: Unicode escape must use braces \\u{...}.") - - # Invalid Unicode escape (empty) - self.make_error_test("Char Unicode Empty", - "'\\u{}'", - "Invalid character literal: empty Unicode escape sequence.") - - # Invalid Unicode escape (too many digits) - self.make_error_test("Char Unicode Too Many Digits", - "'\\u{1234567}'", - "Invalid character literal: Unicode escape sequence too long (max 6 hex digits).") - - # Invalid Unicode escape (invalid code point) - self.make_error_test("Char Unicode Invalid Code Point", - "'\\u{D800}'", - "Invalid character literal: invalid Unicode code point (surrogate range).") - - self.make_error_test("Char Unicode Out Of Range", - "'\\u{110000}'", - "Invalid character literal: Unicode code point out of range (max 0x10FFFF).") - - # Invalid Unicode escape (non-hex digits) - self.make_error_test("Char Unicode Invalid Hex", - "'\\u{GGGG}'", - "Invalid character literal: invalid hexadecimal digit 'G' in Unicode escape.") - - # Unclosed Unicode escape - self.make_error_test("Char Unicode Unclosed", - "'\\u{1F600'", - "Invalid character literal: unclosed Unicode escape sequence.") + if self.ENABLE_UNICODE: + # Invalid Unicode escape (no braces) + self.make_error_test("Char Unicode No Braces", + "'\\u1F600'", + "Invalid character literal: Unicode escape must use braces \\u{...}.") + + # Invalid Unicode escape (empty) + self.make_error_test("Char Unicode Empty", + "'\\u{}'", + "Invalid character literal: empty Unicode escape sequence.") + + # Invalid Unicode escape (too many digits) + self.make_error_test("Char Unicode Too Many Digits", + "'\\u{1234567}'", + "Invalid character literal: Unicode escape sequence too long (max 6 hex digits).") + + # Invalid Unicode escape (invalid code point) + self.make_error_test("Char Unicode Invalid Code Point", + "'\\u{D800}'", + "Invalid character literal: invalid Unicode code point (surrogate range).") + + self.make_error_test("Char Unicode Out Of Range", + "'\\u{110000}'", + "Invalid character literal: Unicode code point out of range (max 0x10FFFF).") + + # Invalid Unicode escape (non-hex digits) + self.make_error_test("Char Unicode Invalid Hex", + "'\\u{GGGG}'", + "Invalid character literal: invalid hexadecimal digit 'G' in Unicode escape.") + + # Unclosed Unicode escape + self.make_error_test("Char Unicode Unclosed", + "'\\u{1F600'", + "Invalid character literal: unclosed Unicode escape sequence.") # Double quotes instead of single self.make_error_test("Char Double Quotes", @@ -263,29 +266,30 @@ class CharTestGenerator(BaseTestGenerator): self.make_success_test("Char Extended ASCII Lower", "'\\x80'", "char", '\x80') self.make_success_test("Char Extended ASCII Upper", "'\\xFF'", "char", '\xFF') - # Zero-width characters - self.make_success_test("Char Zero Width Space", "'\\u{200B}'", "char", '\u200B') - self.make_success_test("Char Zero Width Joiner", "'\\u{200D}'", "char", '\u200D') - - # Right-to-left marks - self.make_success_test("Char RTL Mark", "'\\u{200F}'", "char", '\u200F') - - # Combining characters - self.make_success_test("Char Combining Acute", "'\\u{0301}'", "char", '\u0301') - - # Low Unicode values - self.make_success_test("Char Unicode Zero", "'\\u{0}'", "char", '\0') - self.make_success_test("Char Unicode One", "'\\u{1}'", "char", '\x01') - - # High Unicode values (but valid) - self.make_success_test("Char Unicode High Valid", "'\\u{10FFFF}'", "char", '\U0010FFFF') + if self.ENABLE_UNICODE: + # Zero-width characters + self.make_success_test("Char Zero Width Space", "'\\u{200B}'", "char", '\u200B') + self.make_success_test("Char Zero Width Joiner", "'\\u{200D}'", "char", '\u200D') + + # Right-to-left marks + self.make_success_test("Char RTL Mark", "'\\u{200F}'", "char", '\u200F') + + # Combining characters + self.make_success_test("Char Combining Acute", "'\\u{0301}'", "char", '\u0301') + + # Low Unicode values + self.make_success_test("Char Unicode Zero", "'\\u{0}'", "char", '\0') + self.make_success_test("Char Unicode One", "'\\u{1}'", "char", '\x01') + + # High Unicode values (but valid) + self.make_success_test("Char Unicode High Valid", "'\\u{10FFFF}'", "char", '\U0010FFFF') # Backslash before valid character self.make_success_test("Char Backslash Literal", "'\\\\'", "char", '\\') # Quote escaping self.make_success_test("Char Single Quote Escaped", "'\\''", "char", "'") - self.make_success_test("Char Double Quote Escaped", "'\\\"'", "char", '"') + # self.make_success_test("Char Double Quote Escaped", "'\\\"'", "char", '"') def generate_case_sensitivity_tests(self): """Generate tests for case sensitivity in escape sequences.""" @@ -297,13 +301,14 @@ class CharTestGenerator(BaseTestGenerator): self.make_success_test("Char Hex Digits Lowercase", "'\\xff'", "char", '\xff') self.make_success_test("Char Hex Digits Mixed", "'\\xAb'", "char", '\xAB') - # Unicode escapes - lowercase u - self.make_success_test("Char Unicode Lowercase u", "'\\u{41}'", "char", 'A') - - # Unicode hex digits - both cases - self.make_success_test("Char Unicode Hex Uppercase", "'\\u{1F600}'", "char", '😀') - self.make_success_test("Char Unicode Hex Lowercase", "'\\u{1f600}'", "char", '😀') - self.make_success_test("Char Unicode Hex Mixed", "'\\u{1F60a}'", "char", '😊') + if self.ENABLE_UNICODE: + # Unicode escapes - lowercase u + self.make_success_test("Char Unicode Lowercase u", "'\\u{41}'", "char", 'A') + + # Unicode hex digits - both cases + self.make_success_test("Char Unicode Hex Uppercase", "'\\u{1F600}'", "char", '😀') + self.make_success_test("Char Unicode Hex Lowercase", "'\\u{1f600}'", "char", '😀') + self.make_success_test("Char Unicode Hex Mixed", "'\\u{1F60a}'", "char", '😊') def generate_all_tests(self) -> List[Dict[str, Any]]: """Generate all character literal test cases.""" @@ -316,11 +321,12 @@ class CharTestGenerator(BaseTestGenerator): # Hexadecimal escapes self.generate_hexadecimal_escape_tests() - # Unicode escapes - self.generate_unicode_escape_tests() - - # Direct Unicode characters - self.generate_unicode_direct_tests() + if self.ENABLE_UNICODE: + # Unicode escapes + self.generate_unicode_escape_tests() + + # Direct Unicode characters + self.generate_unicode_direct_tests() # Whitespace handling self.generate_whitespace_tests() diff --git a/SLS_Tests/generate_tests/float_tests.py b/SLS_Tests/generate_tests/float_tests.py index 302ecd0..1766391 100644 --- a/SLS_Tests/generate_tests/float_tests.py +++ b/SLS_Tests/generate_tests/float_tests.py @@ -287,7 +287,7 @@ class FloatTestGenerator(BaseTestGenerator): self.generate_underscore_tests() # Special values (inf, nan) - self.generate_special_value_tests() + # self.generate_special_value_tests() # Edge cases for each type for type_name in ['f32', 'f64']: diff --git a/SLS_Tests/yaml_to_c_tests.py b/SLS_Tests/yaml_to_c_tests.py index c70b5af..79acc50 100644 --- a/SLS_Tests/yaml_to_c_tests.py +++ b/SLS_Tests/yaml_to_c_tests.py @@ -68,6 +68,12 @@ def _token_to_c_call(token: dict, idx_var="i") -> str: 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 == "f64": + return f'test_double_value(&test, result, {idx_var}++, &(double){{{value}}})' + elif ttype == "f32": + return f'test_float_value(&test, result, {idx_var}++, &(float){{{value}}})' + elif ttype == "char": + return f'test_character_value(&test, result, {idx_var}++, &(uint8_t){{{ord(value)}}})' # type: ignore elif ttype == "identifier": return f'test_identifier_value(&test, result, {idx_var}++, &(TestIdentifierValue){{FALSE, {len(value)}, "{value}"}})' # type: ignore elif ttype == "identifier_literal":