diff --git a/parser/sqlfn.py b/parser/sqlfn.py index 4616bd2..35f68ad 100644 --- a/parser/sqlfn.py +++ b/parser/sqlfn.py @@ -302,6 +302,35 @@ def lint_ea_sqlfn(idl): return bad +# Relative-position MEOS-C functions are named _...; their @csqlfn must point at +# the _... wrapper carrying the matching @sqlfn. The same class of copy-paste as +# lint_ea_sqlfn bites the time axis: a 1-D span reuses ONE value wrapper for both its +# value axis (left/right) and its time axis (before/after), so a time function tagged +# `@csqlfn #Left_span_value()` resolves to the value name `left` and the binding emits +# `left(tstzspan,...)` instead of `before(...)`. The function-name prefix is the SoT. +_POSITIONAL_OPS = { + "left", "right", "overleft", "overright", + "before", "after", "overbefore", "overafter", + "below", "above", "overbelow", "overabove", + "front", "back", "overfront", "overback", +} +_POSITIONAL_NAME = re.compile( + r"^(" + "|".join(sorted(_POSITIONAL_OPS, key=len, reverse=True)) + r")_") + + +def lint_positional_sqlfn(idl): + """Return [(meos_c_name, sqlfn)] where a relative-position function's name prefix + (before_/left_/...) contradicts its resolved @sqlfn — a source @csqlfn mistag that + mis-names one axis of a shared value/time position wrapper.""" + bad = [] + for f in idl["functions"]: + sf = f.get("sqlfn") + m = _POSITIONAL_NAME.match(f["name"]) + if sf and m and sf in _POSITIONAL_OPS and sf != m.group(1): + bad.append((f["name"], sf)) + return bad + + def lint_sqlfn_case_collisions(idl): """Return [(lower, [spelling, ...])] for @sqlfn names that collide case-insensitively but differ in case (e.g. tDistance vs tdistance). diff --git a/run.py b/run.py index de069f7..72f7b74 100644 --- a/run.py +++ b/run.py @@ -12,7 +12,8 @@ from parser.nullable import merge_nullable from parser.outparam import merge_outparams from parser.enrich import enrich_idl -from parser.sqlfn import attach_sqlfn_map, lint_ea_sqlfn, lint_sqlfn_case_collisions +from parser.sqlfn import (attach_sqlfn_map, lint_ea_sqlfn, lint_positional_sqlfn, + lint_sqlfn_case_collisions) from parser.doxygroup import attach_groups from parser.extractors import find_unlisted_foreign_structs from parser.object_model import attach_object_model, find_mobilitydb_src @@ -117,6 +118,17 @@ def main(): f"spelling at the MEOS-C source — binding-breaking otherwise):", file=sys.stderr) for _lo, spellings in case_bad: print(f" {' vs '.join(spellings)}", file=sys.stderr) + # Guard: a relative-position function whose name prefix (before_/left_/...) + # disagrees with its resolved @sqlfn — a shared value/time position wrapper + # whose single @sqlfn mis-names the other axis (before_span_* -> left). The + # name prefix is the SoT; fix the @csqlfn / add a dedicated wrapper at source. + pos_bad = lint_positional_sqlfn(idl) + if pos_bad: + print(f" ⚠ {len(pos_bad)} positional name/@sqlfn mismatch(es) (a time-axis " + f"function resolved to the value name or vice versa — fix at source):", + file=sys.stderr) + for cname, sf in pos_bad: + print(f" {cname} -> @sqlfn {sf}", file=sys.stderr) # Now that both the @sqlfn/@sqlop map (step 4) and the portable bare-name map # (step 3) are attached, classify the shared bbox-topological BACKING tags