Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions gitgalaxy/core/detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -3377,6 +3377,45 @@ def _count_haskell_pattern_list(self, text: str) -> int:
i += 1
return count

def _count_tcl_arg_list(self, text: str) -> int:
"""
Counts Tcl argument list parameters, aware of brace nesting.
Tcl uses {name default_value} for optional arguments. This entire
nested brace structure counts as a single parameter.
Whitespace separates parameters only at depth 0.
"""
depth = 0
count = 0
at_boundary = True
i = 0
while i < len(text):
ch = text[i]
if ch == "\\":
i += 2
continue
if ch == "{":
if depth == 0 and at_boundary:
count += 1
at_boundary = False
depth += 1
i += 1
continue
if ch == "}":
if depth > 0:
depth -= 1
i += 1
continue
if ch in " \t\r\n":
if depth == 0:
at_boundary = True
i += 1
continue
if depth == 0 and at_boundary:
count += 1
at_boundary = False
i += 1
return count

def _calculate_block_metrics(
self,
name: str,
Expand Down Expand Up @@ -3479,6 +3518,7 @@ def _calculate_block_metrics(
arrow_count_groups = rules.get("_args_arrow_count_groups")
colon_selector_groups = rules.get("_args_colon_selector_groups")
pattern_list_groups = rules.get("_args_pattern_list_groups")
tcl_pattern_list_groups = rules.get("_args_tcl_pattern_list_groups")
findall_max_groups = rules.get("_args_findall_max_groups")
findall_sum_groups = rules.get("_args_findall_sum_groups")
if findall_max_groups and arg_match.lastindex in findall_max_groups:
Expand Down Expand Up @@ -3526,6 +3566,11 @@ def _calculate_block_metrics(
else:
total += 1
args_count = total
elif tcl_pattern_list_groups and arg_match.lastindex in tcl_pattern_list_groups:
# Tcl default-value braces (#1512):
# Tcl allows nested braces like {db db} for default
# parameter values, which should count as a single argument.
args_count = self._count_tcl_arg_list(stripped)
elif pattern_list_groups and arg_match.lastindex in pattern_list_groups:
# Haskell signature-less equation LHS (#1505 follow-up):
# a naive whitespace split would wrongly split a single
Expand Down
2 changes: 2 additions & 0 deletions gitgalaxy/standards/language_standards.py
Original file line number Diff line number Diff line change
Expand Up @@ -12734,6 +12734,8 @@ class PrismConfigSchema(TypedDict):
r"^[ \t]*proc[ \t\n]+[a-zA-Z0-9_:\-!?]+[ \t\n]+\{((?:[^{}]|\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\})*)\}",
re.M,
),
# Tcl default-value argument lists (#1512): opt-in for depth-aware braced parameter parsing.
"_args_tcl_pattern_list_groups": {1},
# 3. linear (Sequential Boundaries)
# Structural boundaries. EXCLUDES: global/upvar (globals/heat).
"structural_boundaries": re.compile(r"\b(?:proc|return|break|continue|namespace|variable|yield)\b"),
Expand Down
2 changes: 2 additions & 0 deletions tests/extraction/languages/test_tcl.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
("proc TargetFunc {a b} {", "a b"),
("proc ::namespace::TargetFunc {args} {", "args"),
("proc TargetFunc {{a 1} b} {", "{a 1} b"),
("proc faultsim_integrity_check {{db db}} {", "{db db}"),
("proc TargetFunc {a {b 2} {c {nested list}}} {", "a {b 2} {c {nested list}}"),
],
"invalid": [
"TargetFunc a b",
Expand Down
Loading