tinycwrap 0.0.5__tar.gz → 0.0.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tinycwrap-0.0.5 → tinycwrap-0.0.7}/PKG-INFO +1 -1
- {tinycwrap-0.0.5 → tinycwrap-0.0.7}/pyproject.toml +1 -1
- {tinycwrap-0.0.5 → tinycwrap-0.0.7}/tests/test_kernels.py +7 -0
- {tinycwrap-0.0.5 → tinycwrap-0.0.7}/tinycwrap/__init__.py +1 -1
- {tinycwrap-0.0.5 → tinycwrap-0.0.7}/tinycwrap/cmodule.py +184 -30
- {tinycwrap-0.0.5 → tinycwrap-0.0.7}/tinycwrap/parsing.py +4 -1
- {tinycwrap-0.0.5 → tinycwrap-0.0.7}/tinycwrap.egg-info/PKG-INFO +1 -1
- {tinycwrap-0.0.5 → tinycwrap-0.0.7}/README.md +0 -0
- {tinycwrap-0.0.5 → tinycwrap-0.0.7}/setup.cfg +0 -0
- {tinycwrap-0.0.5 → tinycwrap-0.0.7}/tests/test_geom.py +0 -0
- {tinycwrap-0.0.5 → tinycwrap-0.0.7}/tests/test_path.py +0 -0
- {tinycwrap-0.0.5 → tinycwrap-0.0.7}/tinycwrap.egg-info/SOURCES.txt +0 -0
- {tinycwrap-0.0.5 → tinycwrap-0.0.7}/tinycwrap.egg-info/dependency_links.txt +0 -0
- {tinycwrap-0.0.5 → tinycwrap-0.0.7}/tinycwrap.egg-info/requires.txt +0 -0
- {tinycwrap-0.0.5 → tinycwrap-0.0.7}/tinycwrap.egg-info/top_level.txt +0 -0
|
@@ -88,6 +88,13 @@ def test_merge_sorted(cm):
|
|
|
88
88
|
assert out_len_val == 4
|
|
89
89
|
|
|
90
90
|
|
|
91
|
+
def test_owned_array(cm):
|
|
92
|
+
arr, n = cm.alloc_random_array()
|
|
93
|
+
assert arr.shape[0] == n
|
|
94
|
+
assert n >= 3
|
|
95
|
+
assert np.all(arr[:n] >= 1.0)
|
|
96
|
+
|
|
97
|
+
|
|
91
98
|
def test_struct_output_array(cm):
|
|
92
99
|
n = 4
|
|
93
100
|
particles = cm.Particle.zeros(n)
|
|
@@ -11,6 +11,7 @@ from cffi import FFI
|
|
|
11
11
|
from .parsing import (
|
|
12
12
|
FuncSpec,
|
|
13
13
|
StructSpec,
|
|
14
|
+
base_type_from_ctype,
|
|
14
15
|
numpy_dtype_for_base_type,
|
|
15
16
|
parse_functions_from_cdef,
|
|
16
17
|
parse_structs_from_cdef,
|
|
@@ -163,6 +164,8 @@ class CModule:
|
|
|
163
164
|
|
|
164
165
|
# Re-parse cdef and attach docs from C source, then create wrappers
|
|
165
166
|
self._func_specs = parse_functions_from_cdef(self._cdef)
|
|
167
|
+
# remove helper prototypes we add for ownership
|
|
168
|
+
self._func_specs.pop("free", None)
|
|
166
169
|
self._struct_specs = parse_structs_from_cdef(self._cdef)
|
|
167
170
|
self._attach_docs_from_source()
|
|
168
171
|
self._mark_length_params_from_contracts()
|
|
@@ -287,6 +290,21 @@ class CModule:
|
|
|
287
290
|
src_wo_pp = re.sub(r"__declspec\s*\([^)]+\)", "", src_wo_pp)
|
|
288
291
|
src_wo_pp = re.sub(r"__asm__\s*\([^)]*\)", "", src_wo_pp)
|
|
289
292
|
|
|
293
|
+
# Keep a version with only top-level text (brace depth 0) to avoid
|
|
294
|
+
# picking up statements inside function bodies.
|
|
295
|
+
top_level_chars = []
|
|
296
|
+
depth = 0
|
|
297
|
+
for ch in src_wo_pp:
|
|
298
|
+
if ch == "{":
|
|
299
|
+
depth += 1
|
|
300
|
+
if depth == 0:
|
|
301
|
+
top_level_chars.append(ch)
|
|
302
|
+
if ch == "}" and depth > 0:
|
|
303
|
+
depth -= 1
|
|
304
|
+
if depth == 0:
|
|
305
|
+
top_level_chars.append("\n")
|
|
306
|
+
top_level_src = "".join(top_level_chars)
|
|
307
|
+
|
|
290
308
|
# regex for function definitions
|
|
291
309
|
func_def_re = re.compile(
|
|
292
310
|
r"""
|
|
@@ -311,11 +329,15 @@ class CModule:
|
|
|
311
329
|
r"typedef\s+struct\s+(?:\w+\s*)?{(?P<body>[^}]*)}\s*(?P<name>\w+)\s*;",
|
|
312
330
|
re.DOTALL,
|
|
313
331
|
)
|
|
332
|
+
seen_structs = set()
|
|
314
333
|
for m in struct_re.finditer(src_wo_pp):
|
|
315
|
-
struct_text = m.group(0)
|
|
316
|
-
|
|
334
|
+
struct_text = m.group(0).strip()
|
|
335
|
+
if struct_text not in seen_structs:
|
|
336
|
+
struct_defs.append(struct_text)
|
|
337
|
+
seen_structs.add(struct_text)
|
|
317
338
|
|
|
318
339
|
proto_set = set()
|
|
340
|
+
proto_name_set = set()
|
|
319
341
|
for m in func_def_re.finditer(src_wo_pp):
|
|
320
342
|
if m.group("prefix") and "static" in m.group("prefix"):
|
|
321
343
|
# ignore static functions, not exported
|
|
@@ -339,12 +361,46 @@ class CModule:
|
|
|
339
361
|
continue
|
|
340
362
|
args = " ".join(strip_restrict_keywords(m.group("args")).split())
|
|
341
363
|
proto = f"{ret} {name}({args});"
|
|
342
|
-
if
|
|
364
|
+
if name not in proto_name_set:
|
|
365
|
+
prototypes.append(proto)
|
|
366
|
+
proto_set.add(proto)
|
|
367
|
+
proto_name_set.add(name)
|
|
368
|
+
|
|
369
|
+
# also pick up function declarations (without body), e.g., from headers
|
|
370
|
+
decl_re = re.compile(r"([A-Za-z_][A-Za-z0-9_\s\*]*?)\s+([A-Za-z_]\w*)\s*\(([^)]*)\)\s*;")
|
|
371
|
+
for m in decl_re.finditer(top_level_src):
|
|
372
|
+
if "return" in m.group(0) or "=" in m.group(0):
|
|
373
|
+
continue
|
|
374
|
+
ret = " ".join(strip_restrict_keywords(m.group(1)).split())
|
|
375
|
+
if "static" in ret.split():
|
|
376
|
+
continue
|
|
377
|
+
name = m.group(2)
|
|
378
|
+
args = " ".join(strip_restrict_keywords(m.group(3)).split())
|
|
379
|
+
proto = f"{ret} {name}({args});"
|
|
380
|
+
if name not in proto_name_set:
|
|
343
381
|
prototypes.append(proto)
|
|
344
382
|
proto_set.add(proto)
|
|
383
|
+
proto_name_set.add(name)
|
|
345
384
|
|
|
346
385
|
if not prototypes and not struct_defs:
|
|
347
386
|
raise RuntimeError(f"No functions found in {self._c_path} to generate cdef")
|
|
387
|
+
# fallback: if we missed pointer-returning prototypes present as lines
|
|
388
|
+
type_prefix_re = re.compile(r"^(void|int|float|double|long|unsigned|signed|struct|char)\b")
|
|
389
|
+
for line in top_level_src.splitlines():
|
|
390
|
+
line_clean = line.strip()
|
|
391
|
+
if not line_clean or line_clean.startswith("typedef") or ":" in line_clean:
|
|
392
|
+
continue
|
|
393
|
+
if not type_prefix_re.match(line_clean):
|
|
394
|
+
continue
|
|
395
|
+
if "=" in line_clean:
|
|
396
|
+
continue
|
|
397
|
+
if "(" in line_clean and ")" in line_clean and line_clean.endswith(";"):
|
|
398
|
+
name_match = re.match(r"[A-Za-z_][A-Za-z0-9_\s\*]*?\s+([A-Za-z_]\w*)\s*\(", line_clean)
|
|
399
|
+
fname = name_match.group(1) if name_match else line_clean
|
|
400
|
+
if fname not in proto_name_set:
|
|
401
|
+
prototypes.append(line_clean)
|
|
402
|
+
proto_set.add(line_clean)
|
|
403
|
+
proto_name_set.add(fname)
|
|
348
404
|
|
|
349
405
|
cdef_parts = []
|
|
350
406
|
if struct_defs:
|
|
@@ -357,6 +413,8 @@ class CModule:
|
|
|
357
413
|
continue
|
|
358
414
|
cdef_lines.append(line)
|
|
359
415
|
cdef = "\n".join(cdef_lines)
|
|
416
|
+
if "free(" not in cdef:
|
|
417
|
+
cdef += "\nvoid free(void *);"
|
|
360
418
|
show = self._verbose if verbose is None else verbose
|
|
361
419
|
if show:
|
|
362
420
|
print("[CModule] Auto-generated cdef:\n" + cdef)
|
|
@@ -380,9 +438,16 @@ class CModule:
|
|
|
380
438
|
doc = re.sub(r"\n\s+", "\n", doc)
|
|
381
439
|
fspec.doc = doc
|
|
382
440
|
contracts = []
|
|
441
|
+
owns: list[str] = []
|
|
383
442
|
for line in doc.splitlines():
|
|
384
443
|
m_contract = re.search(r"(post-)?contract:\s*(.*)", line, flags=re.IGNORECASE)
|
|
385
444
|
if not m_contract:
|
|
445
|
+
m_own = re.search(r"own:\s*(.*)", line, flags=re.IGNORECASE)
|
|
446
|
+
if m_own:
|
|
447
|
+
for name in m_own.group(1).split(","):
|
|
448
|
+
n = name.strip()
|
|
449
|
+
if n:
|
|
450
|
+
owns.append(n)
|
|
386
451
|
continue
|
|
387
452
|
is_post = m_contract.group(1) is not None
|
|
388
453
|
after = m_contract.group(2)
|
|
@@ -398,6 +463,7 @@ class CModule:
|
|
|
398
463
|
expr = mlen.group(2).strip()
|
|
399
464
|
contracts.append((target, expr, is_post))
|
|
400
465
|
fspec.contracts = contracts or None
|
|
466
|
+
fspec.owns = owns or None
|
|
401
467
|
|
|
402
468
|
def _mark_length_params_from_contracts(self):
|
|
403
469
|
"""Mark length-like parameters based solely on explicit contracts."""
|
|
@@ -428,13 +494,14 @@ class CModule:
|
|
|
428
494
|
"size_t",
|
|
429
495
|
"ssize_t",
|
|
430
496
|
)
|
|
431
|
-
and (not arg.is_pointer)
|
|
432
497
|
and arg.name in referenced
|
|
433
498
|
):
|
|
434
499
|
arg.is_length_param = True
|
|
435
500
|
for arg in fspec.args:
|
|
436
501
|
if arg.is_length_param:
|
|
437
502
|
arg.is_scalar = False
|
|
503
|
+
arg.is_array_in = False
|
|
504
|
+
arg.is_array_out = False
|
|
438
505
|
elif (
|
|
439
506
|
(not arg.is_pointer)
|
|
440
507
|
and arg.array_len is None
|
|
@@ -639,6 +706,7 @@ class CModule:
|
|
|
639
706
|
"_self": self,
|
|
640
707
|
"np": np,
|
|
641
708
|
"numpy_dtype_for_base_type": numpy_dtype_for_base_type,
|
|
709
|
+
"base_type_from_ctype": base_type_from_ctype,
|
|
642
710
|
"_struct_classes": self._struct_classes,
|
|
643
711
|
"_struct_dtypes": self._struct_dtypes,
|
|
644
712
|
}
|
|
@@ -664,7 +732,6 @@ class CModule:
|
|
|
664
732
|
Build the Python source string for a wrapper with an explicit signature.
|
|
665
733
|
Keeping this separate allows inspection/debugging of the generated code.
|
|
666
734
|
"""
|
|
667
|
-
src_parts: list[str] = []
|
|
668
735
|
func_text = self._function_source(fspec.name)
|
|
669
736
|
if func_text:
|
|
670
737
|
c_source_text = func_text
|
|
@@ -753,6 +820,7 @@ class CModule:
|
|
|
753
820
|
else:
|
|
754
821
|
contract_map[target] = expr
|
|
755
822
|
|
|
823
|
+
length_pointer_names = {a.name for a in fspec.args if a.is_length_param and a.is_pointer}
|
|
756
824
|
pointer_scalar_names = {
|
|
757
825
|
a.name
|
|
758
826
|
for a in fspec.args
|
|
@@ -773,7 +841,7 @@ class CModule:
|
|
|
773
841
|
"ssize_t",
|
|
774
842
|
)
|
|
775
843
|
)
|
|
776
|
-
}
|
|
844
|
+
} | length_pointer_names
|
|
777
845
|
|
|
778
846
|
func_names = set(self._func_specs.keys())
|
|
779
847
|
|
|
@@ -782,6 +850,7 @@ class CModule:
|
|
|
782
850
|
expr = re.sub(r"len\((\w+)\)", r"len(arr_\1)", expr)
|
|
783
851
|
for name in pointer_scalar_names:
|
|
784
852
|
expr = re.sub(rf"\b{name}\b", f"int(arr_{name}.ravel()[0])", expr)
|
|
853
|
+
expr = re.sub(rf"\b{name}\b", f"scalar_{name}", expr)
|
|
785
854
|
if func_names:
|
|
786
855
|
pattern = r"\b(" + "|".join(re.escape(n) for n in func_names) + r")\s*\(([^()]*)\)"
|
|
787
856
|
|
|
@@ -809,6 +878,17 @@ class CModule:
|
|
|
809
878
|
scalar_lines: list[str] = []
|
|
810
879
|
|
|
811
880
|
for a in fspec.args:
|
|
881
|
+
if a.is_length_param and a.is_pointer:
|
|
882
|
+
base_dtype = "np.dtype('int32')"
|
|
883
|
+
out_lines = [
|
|
884
|
+
f" arr_{a.name} = np.zeros((), dtype={base_dtype})",
|
|
885
|
+
f" ptr_{a.name} = _self._ffi.cast('{a.base_type} *', _self._ffi.from_buffer(arr_{a.name}))",
|
|
886
|
+
]
|
|
887
|
+
call_args.append(f"ptr_{a.name}")
|
|
888
|
+
output_vars.append(f"arr_{a.name}")
|
|
889
|
+
output_names.append(a.name)
|
|
890
|
+
pointer_scalar_outputs.append((a.name, f"arr_{a.name}"))
|
|
891
|
+
continue
|
|
812
892
|
if a.is_array_in:
|
|
813
893
|
const_prefix = "const " if a.is_const else ""
|
|
814
894
|
if a.base_type in struct_names:
|
|
@@ -840,21 +920,25 @@ class CModule:
|
|
|
840
920
|
scalar_lines.append(f" {a.name} = {a.name}")
|
|
841
921
|
call_args.append(a.name)
|
|
842
922
|
elif a.is_length_param:
|
|
843
|
-
if a.
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
f" if {a.name} is None:",
|
|
847
|
-
f" {a.name} = int({expr_py})",
|
|
848
|
-
f" else:",
|
|
849
|
-
f" {a.name} = int({a.name})",
|
|
850
|
-
]
|
|
923
|
+
if a.is_pointer:
|
|
924
|
+
# handled in array/pointer branch
|
|
925
|
+
call_args.append(None)
|
|
851
926
|
else:
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
927
|
+
if a.name in contract_map:
|
|
928
|
+
expr_py = _expr_py(contract_map[a.name])
|
|
929
|
+
length_lines += [
|
|
930
|
+
f" if {a.name} is None:",
|
|
931
|
+
f" {a.name} = int({expr_py})",
|
|
932
|
+
f" else:",
|
|
933
|
+
f" {a.name} = int({a.name})",
|
|
934
|
+
]
|
|
935
|
+
else:
|
|
936
|
+
length_lines += [
|
|
937
|
+
f" if {a.name} is None:",
|
|
938
|
+
f" raise ValueError('{fspec.name}: length parameter {a.name} requires an explicit Contract')",
|
|
939
|
+
f" {a.name} = int({a.name})",
|
|
940
|
+
]
|
|
941
|
+
call_args.append(a.name)
|
|
858
942
|
else:
|
|
859
943
|
# defer outputs / pointer handling
|
|
860
944
|
call_args.append(None) # placeholder
|
|
@@ -955,15 +1039,14 @@ class CModule:
|
|
|
955
1039
|
|
|
956
1040
|
ret_type = fspec.return_ctype.strip()
|
|
957
1041
|
call_expr = f"cfun({', '.join(arg_call_args)})"
|
|
958
|
-
|
|
959
|
-
|
|
1042
|
+
own_return = fspec.owns and "return" in fspec.owns and fspec.return_ctype.strip().endswith("*")
|
|
1043
|
+
if own_return:
|
|
1044
|
+
lines.append(f" res_ptr = {call_expr}")
|
|
960
1045
|
else:
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
expr_py = _expr_py(post_contract_map[out_name])
|
|
966
|
-
lines.append(f" {out_var} = {out_var}[:int({expr_py})]")
|
|
1046
|
+
if ret_type == "void":
|
|
1047
|
+
lines.append(f" {call_expr}")
|
|
1048
|
+
else:
|
|
1049
|
+
lines.append(f" res = {call_expr}")
|
|
967
1050
|
|
|
968
1051
|
for name, arr_var in pointer_scalar_outputs:
|
|
969
1052
|
lines.append(f" scalar_{name} = int(np.asarray({arr_var}).ravel()[0])")
|
|
@@ -972,14 +1055,73 @@ class CModule:
|
|
|
972
1055
|
for name, arr_var, cls_expr in struct_scalar_outputs:
|
|
973
1056
|
lines.append(f" obj_{name} = {cls_expr}()")
|
|
974
1057
|
lines.append(f" object.__setattr__(obj_{name}, '_data', np.array({arr_var}, copy=True))")
|
|
1058
|
+
pointer_scalar_map = {arr: (name, f"scalar_{name}") for name, arr in pointer_scalar_outputs}
|
|
1059
|
+
pairs = list(zip(output_names, output_vars))
|
|
1060
|
+
# place array outputs before scalar pointer lengths
|
|
1061
|
+
pairs_sorted = sorted(pairs, key=lambda p: 1 if p[1] in pointer_scalar_map else 0)
|
|
1062
|
+
output_names_reordered: list[str] = []
|
|
975
1063
|
output_vars_final: list[str] = []
|
|
976
|
-
for ov in
|
|
1064
|
+
for name, ov in pairs_sorted:
|
|
1065
|
+
output_names_reordered.append(name)
|
|
977
1066
|
if ov in struct_scalar_map:
|
|
978
1067
|
n, _ = struct_scalar_map[ov]
|
|
979
1068
|
output_vars_final.append(f"obj_{n}")
|
|
1069
|
+
elif ov in pointer_scalar_map:
|
|
1070
|
+
output_vars_final.append(pointer_scalar_map[ov][1])
|
|
980
1071
|
else:
|
|
981
1072
|
output_vars_final.append(ov)
|
|
982
1073
|
|
|
1074
|
+
own_return_len_expr = None
|
|
1075
|
+
if own_return and contract_map.get("return"):
|
|
1076
|
+
own_return_len_expr = _expr_py(contract_map["return"])
|
|
1077
|
+
|
|
1078
|
+
if own_return:
|
|
1079
|
+
base_ret = base_type_from_ctype(fspec.return_ctype)
|
|
1080
|
+
ret_dtype_expr = f"np.dtype('{np.dtype(numpy_dtype_for_base_type(base_ret)).name}')"
|
|
1081
|
+
lines.append(" lib_free = None")
|
|
1082
|
+
lines.append(" try:")
|
|
1083
|
+
lines.append(" lib_free = _self._lib.free")
|
|
1084
|
+
lines.append(" except AttributeError:")
|
|
1085
|
+
lines.append(" pass")
|
|
1086
|
+
lines.append(" libc_free = None")
|
|
1087
|
+
lines.append(" for _cand in (None, 'libc.so.6', 'libc.so', 'libc.dylib'):")
|
|
1088
|
+
lines.append(" if libc_free is not None:")
|
|
1089
|
+
lines.append(" break")
|
|
1090
|
+
lines.append(" try:")
|
|
1091
|
+
lines.append(" _libc = _self._ffi.dlopen(_cand)")
|
|
1092
|
+
lines.append(" libc_free = getattr(_libc, 'free', None)")
|
|
1093
|
+
lines.append(" except OSError:")
|
|
1094
|
+
lines.append(" continue")
|
|
1095
|
+
lines.append(" free_fn = lib_free or libc_free")
|
|
1096
|
+
lines.append(f" if free_fn is None: raise RuntimeError('{fspec.name}: cannot locate free() for owned return')")
|
|
1097
|
+
if own_return_len_expr is None:
|
|
1098
|
+
lines.append(f" raise ValueError('{fspec.name}: Own return requires len(return)=... Contract')")
|
|
1099
|
+
else:
|
|
1100
|
+
for name, arr_var in pointer_scalar_outputs:
|
|
1101
|
+
if f"scalar_{name}" not in [v for v in output_vars_final]:
|
|
1102
|
+
lines.append(f" scalar_{name} = int(np.asarray({arr_var}).ravel()[0])")
|
|
1103
|
+
# allow len(return)=out_len style expressions that use pointer-scalar values
|
|
1104
|
+
lines.append(f" res_buf = _self._ffi.gc(res_ptr, free_fn)")
|
|
1105
|
+
lines.append(
|
|
1106
|
+
f" arr_ret = np.frombuffer(_self._ffi.buffer(res_buf, int({own_return_len_expr}) * np.dtype({ret_dtype_expr}).itemsize), dtype={ret_dtype_expr})"
|
|
1107
|
+
)
|
|
1108
|
+
ret_parts: list[str] = ["arr_ret"]
|
|
1109
|
+
if output_vars_final:
|
|
1110
|
+
for v in output_vars_final:
|
|
1111
|
+
if v not in ret_parts:
|
|
1112
|
+
ret_parts.append(v)
|
|
1113
|
+
# append any scalar lengths not already in ret_parts
|
|
1114
|
+
for name, _arr in pointer_scalar_outputs:
|
|
1115
|
+
sval = f"scalar_{name}"
|
|
1116
|
+
if sval not in ret_parts:
|
|
1117
|
+
ret_parts.append(sval)
|
|
1118
|
+
if len(ret_parts) == 1:
|
|
1119
|
+
ret_expr = ret_parts[0]
|
|
1120
|
+
else:
|
|
1121
|
+
ret_expr = "(" + ", ".join(ret_parts) + ")"
|
|
1122
|
+
lines.append(f" return {ret_expr}")
|
|
1123
|
+
return "\n".join(lines)
|
|
1124
|
+
|
|
983
1125
|
if output_vars_final:
|
|
984
1126
|
if ret_type == "void":
|
|
985
1127
|
if len(output_vars_final) == 1:
|
|
@@ -991,8 +1133,20 @@ class CModule:
|
|
|
991
1133
|
ret_expr = f"{output_vars_final[0]}, res"
|
|
992
1134
|
else:
|
|
993
1135
|
ret_expr = "(" + ", ".join(output_vars_final) + "), res"
|
|
1136
|
+
# apply post-contract slicing using scalar lengths if available
|
|
1137
|
+
for out_name, out_var in zip(output_names_reordered, output_vars_final):
|
|
1138
|
+
if out_name in post_contract_map:
|
|
1139
|
+
expr_py = _expr_py(post_contract_map[out_name])
|
|
1140
|
+
scalar_names = {n for n, _ in pointer_scalar_outputs}
|
|
1141
|
+
if out_name in scalar_names:
|
|
1142
|
+
expr_py = expr_py.replace(out_name, f"scalar_{out_name}")
|
|
1143
|
+
ret_expr = ret_expr.replace(out_var, f"({out_var})[:int({expr_py})]")
|
|
994
1144
|
if pointer_scalar_outputs:
|
|
995
|
-
scalars = [
|
|
1145
|
+
scalars = [
|
|
1146
|
+
f"scalar_{n}"
|
|
1147
|
+
for n, _ in pointer_scalar_outputs
|
|
1148
|
+
if f"scalar_{n}" not in output_vars_final
|
|
1149
|
+
]
|
|
996
1150
|
if isinstance(ret_expr, str) and ret_expr.startswith("("):
|
|
997
1151
|
ret_expr = (
|
|
998
1152
|
ret_expr[:-1]
|
|
@@ -72,6 +72,7 @@ class FuncSpec:
|
|
|
72
72
|
args: list # list[ArgSpec]
|
|
73
73
|
doc: str | None = None
|
|
74
74
|
contracts: list[tuple[str, str, bool]] | None = None
|
|
75
|
+
owns: list[str] | None = None
|
|
75
76
|
|
|
76
77
|
|
|
77
78
|
@dataclass
|
|
@@ -151,7 +152,9 @@ def _parse_functions_with_pycparser(cdef: str) -> dict[str, FuncSpec]:
|
|
|
151
152
|
for ext in ast.ext:
|
|
152
153
|
if isinstance(ext, c_ast.Decl) and isinstance(ext.type, c_ast.FuncDecl):
|
|
153
154
|
fname = ext.name
|
|
154
|
-
ret_ctype,
|
|
155
|
+
ret_ctype, ret_is_ptr, _, _ = _ctype_from_decl(ext.type.type)
|
|
156
|
+
if ret_is_ptr:
|
|
157
|
+
ret_ctype = ret_ctype + " *"
|
|
155
158
|
argspecs: list[ArgSpec] = []
|
|
156
159
|
args = ext.type.args
|
|
157
160
|
if args and args.params:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|