#!/usr/bin/env python3 """Generate ts_generated.h with all indicator declarations and test registry. Parses lib/*.c for ts_parameter_t declarations and emits: - extern ts_parameter_t const ts__p - uint_t ts__offset(...) - int ts_(...) - bool ts_test_(void) [inside #ifdef TS_IMPLEMENTATION] """ import importlib.util import os import re import sys _spec = importlib.util.spec_from_file_location( "ts_parser", os.path.join(os.path.dirname(os.path.abspath(__file__)), "ts_parser.py"), ) if _spec and _spec.loader: _ts_parser = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_ts_parser) parse_all = _ts_parser.parse_all else: print("Error: could not load ts_parser", file=sys.stderr) sys.exit(1) ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) TEST_DIR = os.path.join(ROOT, "test") OUT_H = os.path.join(ROOT, "ts_generated.h") OUT_TEST = os.path.join(TEST_DIR, "main_generated.c") def generate_header(funcs): """Generate ts_generated.h.""" lines = [] lines.append("/* Auto-generated indicator declarations. Do not edit. */") lines.append("") lines.append("#ifndef TS_GENERATED_H") lines.append("#define TS_GENERATED_H") lines.append("") for fm in funcs: lines.append("extern ts_parameter_t const ts_" + fm.name + "_p;") lines.append("uint_t ts_" + fm.name + "_offset( ts_constant_t const * );") lines.append( "int ts_" + fm.name + "( fp_t * const *y, uint_t y_n, fp_t const * const *x, " "uint_t x_n, uint_t n, ts_constant_t const *c );" ) lines.append("") lines.append("#ifdef TS_IMPLEMENTATION") lines.append("") for fm in funcs: lines.append("bool ts_test_" + fm.name + "( void );") lines.append("") lines.append("#endif /* TS_IMPLEMENTATION */") lines.append("") lines.append("#endif /* TS_GENERATED_H */") lines.append("") return "\n".join(lines) def generate_test_main(funcs): """Generate test/main_generated.c with extern declarations and test array.""" lines = [] lines.append("/* Auto-generated test registry. Do not edit. */") lines.append("") lines.append("#define EXTERN_TEST(name) extern bool ts_test_##name(void)") for fm in funcs: lines.append("EXTERN_TEST(" + fm.name + ");") lines.append("#undef EXTERN_TEST") lines.append("") lines.append("typedef struct {") lines.append(" const char *name;") lines.append(" bool (*func)(void);") lines.append("} test_case_t;") lines.append("") lines.append("#define TEST_ENTRY(name) { #name, ts_test_##name }") lines.append("") lines.append("static test_case_t tests[] = {") for fm in funcs: lines.append(" TEST_ENTRY(" + fm.name + "),") lines.append("};") lines.append("") lines.append("#define NUM_TESTS (sizeof(tests) / sizeof(tests[0]))") lines.append("") lines.append("#undef TEST_ENTRY") lines.append("") return "\n".join(lines) def _is_valid_c_identifier(name): return bool(re.match(r"^[a-zA-Z_][a-zA-Z0-9_]*$", name)) def main(): funcs = parse_all(detect_x_access=False) if not funcs: print("Warning: no ts_parameter declarations found.", file=sys.stderr) return 1 for fm in funcs: if not _is_valid_c_identifier(fm.name): print(f"Error: invalid C identifier '{fm.name}'", file=sys.stderr) return 1 os.makedirs(TEST_DIR, exist_ok=True) try: with open(OUT_H, "w", encoding="utf-8") as f: f.write(generate_header(funcs)) except OSError as e: print(f"Error writing {OUT_H}: {e}", file=sys.stderr) return 1 try: with open(OUT_TEST, "w", encoding="utf-8") as f: f.write(generate_test_main(funcs)) except OSError as e: print(f"Error writing {OUT_TEST}: {e}", file=sys.stderr) return 1 print(f"Generated {len(funcs)} declarations -> {OUT_H}") print(f"Generated test registry -> {OUT_TEST}") return 0 if __name__ == "__main__": sys.exit(main())