121 lines
4.0 KiB
Python
121 lines
4.0 KiB
Python
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 <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
|
|
#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)
|