1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
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())
|