diff --git a/SLS_C/tests/lexer_tests.c b/SLS_C/tests/lexer_tests.c index 76c95bc..ed9aa97 100644 --- a/SLS_C/tests/lexer_tests.c +++ b/SLS_C/tests/lexer_tests.c @@ -15,12 +15,10 @@ #include "tests/lexer_test_helpers.h" #include "tests/tests.h" + static const size_t NUM_OF_TESTS = 14; - -// Test cases - -static TestResult test_empty_statement() { - LexerTest test = start_up_test("test_empty_statement", ""); +static TestResult test_Empty_Statement() { + LexerTest test = start_up_test("test_Empty_Statement", ""); LexerResult result = lexical_analysis(&test.lexer_info); if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error); size_t i = 0; @@ -28,169 +26,137 @@ static TestResult test_empty_statement() { return pass_test(&test, result); } -static TestResult test_hello_world_statement() { - LexerTest test = start_up_test("test_hello_world_statement", "\"Hello, World!\" print"); +static TestResult test_Identifier_Hello() { + LexerTest test = start_up_test("test_Identifier_Hello", "Hello"); 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_string_value(&test, result, i++, &(TestStringValue){13, "Hello, World!"})) return test.result; - if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 5, "print"})) return test.result; + if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 5, "Hello"})) return test.result; if (test_eof_value(&test, result, i++, 0)) return test.result; return pass_test(&test, result); } -static TestResult test_add_statement() { - LexerTest test = start_up_test("test_add_statement", "3 4 +"); +static TestResult test_Identifier_Plus() { + LexerTest test = start_up_test("test_Identifier_Plus", "+"); 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_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 3})) return test.result; - if (test_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 4})) return test.result; if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 1, "+"})) return test.result; if (test_eof_value(&test, result, i++, 0)) return test.result; return pass_test(&test, result); } -static TestResult test_sub_statement() { - LexerTest test = start_up_test("test_sub_statement", "10 3 -"); +static TestResult test_Identifier_Rotate() { + LexerTest test = start_up_test("test_Identifier_Rotate", "rot"); 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_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 10})) return test.result; - if (test_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 3})) return test.result; - if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 1, "-"})) return test.result; + if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 3, "rot"})) return test.result; if (test_eof_value(&test, result, i++, 0)) return test.result; return pass_test(&test, result); } -static TestResult test_mult_statement() { - LexerTest test = start_up_test("test_mult_statement", "5 6 *"); +static TestResult test_Identifier_Swap_and_Duplicate() { + LexerTest test = start_up_test("test_Identifier_Swap_and_Duplicate", "swap dup"); 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_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 5})) return test.result; - if (test_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 6})) return test.result; - if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 1, "*"})) return test.result; - if (test_eof_value(&test, result, i++, 0)) return test.result; - return pass_test(&test, result); -} - -static TestResult test_div_statement() { - LexerTest test = start_up_test("test_div_statement", "20 4 /"); - 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_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 20})) return test.result; - if (test_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 4})) return test.result; - if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 1, "/"})) return test.result; - if (test_eof_value(&test, result, i++, 0)) return test.result; - return pass_test(&test, result); -} - -static TestResult test_add_and_mult_statement() { - LexerTest test = start_up_test("test_add_and_mult_statement", "2 3 + 4 *"); - 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_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 2})) return test.result; - if (test_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 3})) return test.result; - if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 1, "+"})) return test.result; - if (test_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 4})) return test.result; - if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 1, "*"})) return test.result; - if (test_eof_value(&test, result, i++, 0)) return test.result; - return pass_test(&test, result); -} - -static TestResult test_dup_and_mult_statement() { - LexerTest test = start_up_test("test_dup_and_mult_statement", "10 dup *"); - 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_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 10})) return test.result; - if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 3, "dup"})) return test.result; - if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 1, "*"})) return test.result; - if (test_eof_value(&test, result, i++, 0)) return test.result; - return pass_test(&test, result); -} - -static TestResult test_square_fn() { - LexerTest test = start_up_test("test_dup_statement", "(Number -- Number) { dup * } ::square fn"); - 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_type_tuple_value(&test, result, i++, &(TestTypeTupleValue){1, (TestIdentifierValue[]){(TestIdentifierValue){TRUE, 6, "Number"}}, 1, (TestIdentifierValue[]){(TestIdentifierValue){TRUE, 6, "Number"}}})) return test.result; - if (test_token_string_value(&test, result, i++, &(TestTokenStringValue){3, (TestTokenStringToken[]){ - (TestTokenStringToken){(Boolean (*)(LexerTest *, LexerResult, size_t, void *))test_identifier_value, &(TestIdentifierValue){FALSE, 3, "dup"}}, - (TestTokenStringToken){(Boolean (*)(LexerTest *, LexerResult, size_t, void *))test_identifier_value, &(TestIdentifierValue){FALSE, 1, "*"}} - }})) return test.result; - if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){TRUE, 6, "square"})) return test.result; - if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 2, "fn"})) return test.result; - if (test_eof_value(&test, result, i++, 0)) return test.result; - return pass_test(&test, result); -} - -static TestResult test_dup_statement() { - LexerTest test = start_up_test("test_dup_statement", "5 dup"); - 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_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 5})) return test.result; + if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 4, "swap"})) return test.result; if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 3, "dup"})) return test.result; if (test_eof_value(&test, result, i++, 0)) return test.result; return pass_test(&test, result); } -static TestResult test_swap_statement() { - LexerTest test = start_up_test("test_swap_statement", "5 10 swap"); +static TestResult test_Identifier_Depth() { + LexerTest test = start_up_test("test_Identifier_Depth", "depth"); + 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_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 5, "depth"})) return test.result; + if (test_eof_value(&test, result, i++, 0)) return test.result; + return pass_test(&test, result); +} + +static TestResult test_Identifier_Literal_Point() { + LexerTest test = start_up_test("test_Identifier_Literal_Point", "::Point"); + 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_identifier_value(&test, result, i++, &(TestIdentifierValue){TRUE, 5, "Point"})) return test.result; + if (test_eof_value(&test, result, i++, 0)) return test.result; + return pass_test(&test, result); +} + +static TestResult test_Identifier_Literal_Multiply() { + LexerTest test = start_up_test("test_Identifier_Literal_Multiply", "::*"); + 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_identifier_value(&test, result, i++, &(TestIdentifierValue){TRUE, 1, "*"})) return test.result; + if (test_eof_value(&test, result, i++, 0)) return test.result; + return pass_test(&test, result); +} + +static TestResult test_Identifier_Literal_Name() { + LexerTest test = start_up_test("test_Identifier_Literal_Name", "::name"); + 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_identifier_value(&test, result, i++, &(TestIdentifierValue){TRUE, 4, "name"})) return test.result; + if (test_eof_value(&test, result, i++, 0)) return test.result; + return pass_test(&test, result); +} + +static TestResult test_Integer_Default_Decimal_15() { + LexerTest test = start_up_test("test_Integer_Default_Decimal_15", "15"); + 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_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 15})) return test.result; + if (test_eof_value(&test, result, i++, 0)) return test.result; + return pass_test(&test, result); +} + +static TestResult test_Integer_Default_Hex_E1() { + LexerTest test = start_up_test("test_Integer_Default_Hex_E1", "0xE1"); + 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_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 225})) return test.result; + if (test_eof_value(&test, result, i++, 0)) return test.result; + return pass_test(&test, result); +} + +static TestResult test_Integer_Default_Hex_b2() { + LexerTest test = start_up_test("test_Integer_Default_Hex_b2", "0xb2"); + 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_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 178})) return test.result; + if (test_eof_value(&test, result, i++, 0)) return test.result; + return pass_test(&test, result); +} + +static TestResult test_Integer_Default_Binary_1010() { + LexerTest test = start_up_test("test_Integer_Default_Binary_1010", "0b1010"); 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_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 5})) return test.result; if (test_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 10})) return test.result; - if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 3, "swap"})) return test.result; if (test_eof_value(&test, result, i++, 0)) return test.result; return pass_test(&test, result); } -static TestResult test_over_statement() { - LexerTest test = start_up_test("test_over_statement", "5 10 over"); +static TestResult test_Integer_Default_Decimal_2_001_650() { + LexerTest test = start_up_test("test_Integer_Default_Decimal_2_001_650", "2_001_650"); 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_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 5})) return test.result; - if (test_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 10})) return test.result; - if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 3, "over"})) return test.result; + if (test_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 2001650})) return test.result; if (test_eof_value(&test, result, i++, 0)) return test.result; return pass_test(&test, result); } -static TestResult test_rot_statement() { - LexerTest test = start_up_test("test_rot_statement", "1 2 3 rot"); - 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_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 1})) return test.result; - if (test_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 2})) return test.result; - if (test_integer_value(&test, result, i++, &(TestIntegerValue){INTEGER_I64, 3})) return test.result; - if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 3, "rot"})) return test.result; - if (test_eof_value(&test, result, i++, 0)) return test.result; - return pass_test(&test, result); -} - -static TestResult test_swap_and_rot_statement() { - LexerTest test = start_up_test("test_swap_and_rot_statement", "swap rot rot"); - 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_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 3, "swap"})) return test.result; - if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 3, "rot"})) return test.result; - if (test_identifier_value(&test, result, i++, &(TestIdentifierValue){FALSE, 3, "rot"})) return test.result; - if (test_eof_value(&test, result, i++, 0)) return test.result; - return pass_test(&test, result); -} - -// Lexer Tests Runner - TestsReport run_lexer_tests() { TestsReport test_report = (TestsReport) { .section = "lexer_tests", @@ -200,20 +166,20 @@ TestsReport run_lexer_tests() { size_t i = 0; - test_report.tests[i++] = test_empty_statement(); - test_report.tests[i++] = test_hello_world_statement(); - test_report.tests[i++] = test_add_statement(); - test_report.tests[i++] = test_sub_statement(); - test_report.tests[i++] = test_mult_statement(); - test_report.tests[i++] = test_div_statement(); - test_report.tests[i++] = test_add_and_mult_statement(); - test_report.tests[i++] = test_dup_and_mult_statement(); - test_report.tests[i++] = test_square_fn(); - test_report.tests[i++] = test_dup_statement(); - test_report.tests[i++] = test_swap_statement(); - test_report.tests[i++] = test_over_statement(); - test_report.tests[i++] = test_rot_statement(); - test_report.tests[i++] = test_swap_and_rot_statement(); + test_report.tests[i++] = test_Empty_Statement(); + test_report.tests[i++] = test_Identifier_Hello(); + test_report.tests[i++] = test_Identifier_Plus(); + test_report.tests[i++] = test_Identifier_Rotate(); + test_report.tests[i++] = test_Identifier_Swap_and_Duplicate(); + test_report.tests[i++] = test_Identifier_Depth(); + test_report.tests[i++] = test_Identifier_Literal_Point(); + test_report.tests[i++] = test_Identifier_Literal_Multiply(); + test_report.tests[i++] = test_Identifier_Literal_Name(); + test_report.tests[i++] = test_Integer_Default_Decimal_15(); + test_report.tests[i++] = test_Integer_Default_Hex_E1(); + test_report.tests[i++] = test_Integer_Default_Hex_b2(); + test_report.tests[i++] = test_Integer_Default_Binary_1010(); + test_report.tests[i++] = test_Integer_Default_Decimal_2_001_650(); return test_report; } diff --git a/SLS_Tests/cases.yaml b/SLS_Tests/cases.yaml index db92c34..309b190 100644 --- a/SLS_Tests/cases.yaml +++ b/SLS_Tests/cases.yaml @@ -24,6 +24,12 @@ # runtime_error: # message: Error message. +- name: Empty_Statement + code: "" + tokens: [] + operations: [] + stack_final: [] + # Basic Identifiers - name: Identifier Hello @@ -188,9 +194,9 @@ - type: i64 value: 2001650 -- name: Integer i64 Decimal 5 -- name: Integer i64 Hex 5f -- name: Integer i64 Binary 10110 +# - name: Integer i64 Decimal 5 +# - name: Integer i64 Hex 5f +# - name: Integer i64 Binary 10110 # Basic Floats # Basic Strings diff --git a/SLS_Tests/yaml_to_c_tests.py b/SLS_Tests/yaml_to_c_tests.py new file mode 100644 index 0000000..dc89797 --- /dev/null +++ b/SLS_Tests/yaml_to_c_tests.py @@ -0,0 +1,120 @@ +import yaml +import re +from pathlib import Path + +# python3 SLS_Tests/yaml_to_c_tests.py SLS_Tests/cases.yaml SLS_C/tests/lexer_tests.c + +file_headers = """\ +// Kyler Olsen +// YREA SLS +// Lexer Tests +// October 2025 + +#include +#include +#include +#include +#include + +#include "sls/sls_errors.h" +#include "sls/lexer.h" +#include "sls/string.h" +#include "tests/lexer_test_helpers.h" +#include "tests/tests.h" + +""" + +main_header = """\ +TestsReport run_lexer_tests() { + TestsReport test_report = (TestsReport) { + .section = "lexer_tests", + .count = NUM_OF_TESTS, + .tests = (TestResult *)malloc(sizeof(TestResult) * NUM_OF_TESTS), + }; + + size_t i = 0; +""" + +# === Helper functions === + +def sanitize_name(name: str) -> str: + """Convert test name into a valid C function name.""" + name = re.sub(r"[^a-zA-Z0-9_]", "_", name) + name = re.sub(r"_+", "_", name) + return f"test_{name}" + +def c_string_literal(s: str) -> str: + """Escape quotes for embedding in C string literals.""" + return s.replace('"', '\\"') + +def token_to_c_call(token: dict, idx_var="i") -> str: + """Generate a C 'test_*_value' call based on token type.""" + ttype = token.get("type") + value = token.get("value") + + if ttype == "i64": + return f'if (test_integer_value(&test, result, {idx_var}++, &(TestIntegerValue){{INTEGER_I64, {value}}})) return test.result;' + elif ttype == "identifier": + return f'if (test_identifier_value(&test, result, {idx_var}++, &(TestIdentifierValue){{FALSE, {len(value)}, "{value}"}})) return test.result;' # type: ignore + elif ttype == "identifier_literal": + return f'if (test_identifier_value(&test, result, {idx_var}++, &(TestIdentifierValue){{TRUE, {len(value)}, "{value}"}})) return test.result;' # type: ignore + else: + return f'// Unhandled token type: {ttype}' + +def generate_c_test(test: dict) -> str: + """Convert a single YAML test entry to a C test function.""" + name = sanitize_name(test["name"]) + code = c_string_literal(test["code"]) + tokens = test.get("tokens", []) + + # Function header + c_code = [f"static TestResult {name}() " "{", + f' LexerTest test = start_up_test("{name}", "{code}");', + " LexerResult result = lexical_analysis(&test.lexer_info);", + " if (result.type == SLS_ERROR) return error_fail_test(&test, result, result.error);", + " size_t i = 0;"] + + # Token checks + for token in tokens: + c_code.append(" " + token_to_c_call(token)) + + # EOF check and return + 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("}\n") + + return "\n".join(c_code) + +def yaml_to_c_tests(yaml_path: str, output_path: str): + """Convert YAML test cases into C test code.""" + with open(yaml_path, "r", encoding="utf-8") as f: + tests = yaml.safe_load(f) + + # Ensure we have a list of tests + if not isinstance(tests, list): + raise ValueError("Expected a YAML list of test cases.") + + c_tests = [] + for test in tests: + c_tests.append(generate_c_test(test)) + + program = [ + file_headers, + f"static const size_t NUM_OF_TESTS = {len(tests)};", + "\n".join(c_tests), + main_header, + ] + [f" test_report.tests[i++] = {sanitize_name(test['name'])}();" for test in tests] + program.append("\n return test_report;\n}\n") + + output_code = "\n".join(program) + Path(output_path).write_text(output_code, encoding="utf-8") + print(f" Generated {len(c_tests)} C tests -> {output_path}") + +# === Example usage === +if __name__ == "__main__": + import argparse + parser = argparse.ArgumentParser(description="Convert YAML SLS tests to C lexer tests.") + parser.add_argument("input", help="Path to input YAML test file") + parser.add_argument("output", help="Path to output C file") + args = parser.parse_args() + yaml_to_c_tests(args.input, args.output)