diff options
| author | Ethan Werner <mail@ethanwerner.com> | 2026-07-01 09:42:39 +0400 |
|---|---|---|
| committer | Ethan Werner <mail@ethanwerner.com> | 2026-07-01 09:42:39 +0400 |
| commit | 07e18043145f3d91c8ea7ec3ad41b3c905585277 (patch) | |
| tree | 2bdeae46973f4bdfce263679a4008ac768011f28 /scripts/gen_all.py | |
initial commit: ts time series analysis library v0.1.0
- 354 financial and mathematical time-series indicators
- Uniform C11 API with consistent function signatures
- 349 passing tests with -Werror
- Static and shared library builds
- pkg-config integration
- Python bindings
- Fuzzing and sanitizer support
- Security hardening flags
Diffstat (limited to 'scripts/gen_all.py')
| -rw-r--r-- | scripts/gen_all.py | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/scripts/gen_all.py b/scripts/gen_all.py new file mode 100644 index 0000000..dd9d395 --- /dev/null +++ b/scripts/gen_all.py @@ -0,0 +1,135 @@ +#!/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_<name>_p +- uint_t ts_<name>_offset(...) +- int ts_<name>(...) +- bool ts_test_<name>(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()) |