Skip to content

Commit 7335ad6

Browse files
committed
refactor: Finalize condition handling updates in language readers
This commit completes the refactoring of condition handling across language readers by ensuring all conditions are categorized into distinct types: control flow keywords, logical operators, case keywords, and ternary operators. Key updates include: - Enhanced documentation for the handling of conditions, clarifying the purpose of each category. - Adjustments to the LizardExtension to utilize the new structured approach for logical operators. - Minor code cleanups and improvements to maintain clarity and consistency. These changes contribute to improved maintainability and accuracy in cyclomatic complexity calculations while preserving backward compatibility.
1 parent d474ea7 commit 7335ad6

File tree

17 files changed

+180
-134
lines changed

17 files changed

+180
-134
lines changed

lizard_ext/lizardnonstrict.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,5 @@ class LizardExtension(object): # pylint: disable=R0903
1010
# pylint: disable=W0221
1111
def __call__(self, tokens, reader):
1212
# Remove logical operators from conditions (non-strict mode)
13-
# Uses semantic logical_operators instead of hardcoded list
1413
reader.conditions -= reader.logical_operators
1514
return tokens

lizard_languages/code_reader.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,22 +95,20 @@ class CodeReader:
9595
languages = None
9696
extra_subclasses = set()
9797

98-
# Separated condition categories (new structure)
98+
# Condition categories - separate types that contribute to cyclomatic complexity
9999
_control_flow_keywords = {'if', 'for', 'while', 'catch'}
100100
_logical_operators = {'&&', '||'}
101101
_case_keywords = {'case'}
102102
_ternary_operators = {'?'}
103103

104-
# Backward compatibility: old combined set
105-
# If a subclass defines only _conditions, it will be used
104+
# For compatibility with custom readers that may define _conditions directly
106105
_conditions = None
107106

108107
@classmethod
109108
def _build_conditions(cls):
110109
"""Build combined conditions set from separated categories.
111110
112-
Returns combined set of all condition types for backward compatibility
113-
and default behavior.
111+
Returns combined set of all condition types for CCN calculation.
114112
"""
115113
return (cls._control_flow_keywords |
116114
cls._logical_operators |
@@ -121,14 +119,15 @@ def __init__(self, context):
121119
self.parallel_states = []
122120
self.context = context
123121

124-
# Backward compatibility: if subclass defines _conditions, use it
122+
# Build combined conditions set
125123
if self.__class__._conditions is not None:
124+
# Subclass defines _conditions directly
126125
self.conditions = copy(self.__class__._conditions)
127126
else:
128-
# Use new separated structure
127+
# Build from separated categories
129128
self.conditions = copy(self.__class__._build_conditions())
130129

131-
# Expose individual sets for extensions to use
130+
# Expose individual categories for extensions
132131
self.control_flow_keywords = copy(self.__class__._control_flow_keywords)
133132
self.logical_operators = copy(self.__class__._logical_operators)
134133
self.case_keywords = copy(self.__class__._case_keywords)

lizard_languages/erlang.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ class ErlangReader(CodeReader):
2020
_case_keywords = {'case'}
2121
# Note: '?' in Erlang is a macro expansion operator (e.g., ?MODULE, ?EMPTY_NODE)
2222
# Unlike C-style ternary, it's for compile-time macro substitution
23-
# Decision: Keep it in ternary_operators for CCN counting (historical compatibility)
24-
# Rationale: Macro usage can add complexity to understanding code
23+
# Included in ternary_operators because macro usage adds to code complexity
2524
_ternary_operators = {'?'}
2625

2726
def __init__(self, context):

lizard_languages/gdscript.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ class GDScriptReader(PythonReader):
1515
_logical_operators = {'&&', '||'}
1616
_case_keywords = {'case'}
1717
_ternary_operators = {'?'}
18-
# Note: 'else' was in original but shouldn't add to CCN independently
19-
# Fixed: Added 'elif' which was missing
2018

2119
def __init__(self, context):
2220
super(GDScriptReader, self).__init__(context)

lizard_languages/r.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,8 @@ class RReader(CodeReader, ScriptLanguageMixIn):
1616
_control_flow_keywords = {'if', 'else if', 'for', 'while', 'repeat', 'switch',
1717
'tryCatch', 'try', 'ifelse'} # ifelse is a vectorized control function
1818
# R has both short-circuit (&&, ||) and element-wise (&, |) operators
19-
# Decision: Keep both types in logical_operators because:
20-
# - Even in vectorized context, they represent conditional logic
21-
# - Consistent with other languages that count all logical operators
22-
# - Users can use -Enonstrict to exclude all logical operators if desired
19+
# Both types count toward CCN as they represent conditional logic (vectorized or not)
20+
# Users can use -Enonstrict to exclude logical operators if desired
2321
_logical_operators = {'&&', '||', '&', '|'}
2422
_case_keywords = set()
2523
_ternary_operators = set()

lizard_languages/st.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ class StReader(CodeReader, StCommentsMixin):
2727
'if', 'elsif', 'for', 'while', 'repeat',
2828
'IF', 'ELSIF', 'FOR', 'WHILE', 'REPEAT'
2929
}
30-
# Decision: Add AND/OR operators (they were missing from original)
31-
# ST is case-insensitive, so include both forms
30+
# ST is case-insensitive, so include both lowercase and uppercase forms
3231
_logical_operators = {'and', 'or', 'AND', 'OR'}
3332
_case_keywords = {'case', 'CASE'}
3433
_ternary_operators = set()

lizard_languages/ttcn.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ class TTCNReader(CLikeReader): # pylint: disable=R0903
1515
_logical_operators = {'and', 'or', 'xor'}
1616
_case_keywords = {'case'}
1717
_ternary_operators = set()
18-
# Note: 'else' was in original but shouldn't add to CCN independently
1918

2019
def __init__(self, context):
2120
super(TTCNReader, self).__init__(context)

ongoing/REFACTORING_COMPLETE.md

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,22 @@
22

33
## Status: Production Ready
44

5-
All phases of the conditions refactoring have been successfully completed.
5+
The conditions refactoring is complete. All condition-related constructs are now properly categorized.
66

7-
## What Was Done
7+
## Current Structure
88

9-
Separated mixed condition concepts into 4 distinct categories across the entire Lizard codebase:
9+
Lizard now separates condition concepts into 4 distinct categories:
1010

1111
1. **Control Flow Keywords** - `if`, `for`, `while`, `catch`
1212
2. **Logical Operators** - `&&`, `||`, `and`, `or`
1313
3. **Case Keywords** - `case`, `when`
1414
4. **Ternary Operators** - `?`, `??`, `?:`
1515

16-
## Results
16+
## Implementation Status
1717

1818
-**28 files updated** (1 base + 21 languages + 4 extensions + 2 cleanups)
19-
-**7 bugs fixed** (Perl, Rust, TTCN, GDScript x2, ST, R)
20-
-**8 new tests added** (bug reproduction and validation)
19+
-**All languages properly categorized** (23+ languages)
20+
-**All extensions updated** (semantic names)
2121
-**1021 tests passing** (100% pass rate, 0 regressions)
2222
-**Fully backward compatible** (no breaking changes)
2323

@@ -34,7 +34,7 @@ Separated mixed condition concepts into 4 distinct categories across the entire
3434
## Benefits
3535

3636
- **Clarity**: Each token's purpose is explicit
37-
- **Correctness**: 7 bugs fixed, all edge cases handled
37+
- **Correctness**: All edge cases handled and tested
3838
- **Maintainability**: Extensions use semantic names
3939
- **Extensibility**: Clear API for future enhancements
4040
- **Compatibility**: 100% backward compatible
@@ -43,9 +43,7 @@ Separated mixed condition concepts into 4 distinct categories across the entire
4343

4444
```
4545
1021 tests passing
46-
- 1013 existing regression tests
47-
- 8 new bug reproduction tests
48-
6 tests skipped (unchanged)
46+
6 tests skipped
4947
0 regressions
5048
```
5149

ongoing/VERIFICATION_COMPLETE.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Code Verification - All Historical References Removed ✅
2+
3+
## Verification Date
4+
Completed after Phase 7
5+
6+
## Code Verification
7+
8+
### Old `_conditions` Definitions
9+
```bash
10+
$ grep -r "^\s*_conditions\s*=" lizard_languages/ | grep -v "None" | wc -l
11+
0
12+
```
13+
**0 old-style `_conditions` definitions found**
14+
15+
Only the base class has `_conditions = None` for compatibility:
16+
```bash
17+
$ grep -rn "_conditions = None" lizard_languages/
18+
lizard_languages/code_reader.py:105: _conditions = None
19+
```
20+
**Base class compatibility maintained**
21+
22+
### All Language Readers Updated
23+
All 23+ language readers now use separated categories:
24+
-`_control_flow_keywords`
25+
-`_logical_operators`
26+
-`_case_keywords`
27+
-`_ternary_operators`
28+
29+
### Comments Cleaned
30+
All historical references removed from:
31+
-`erlang.py` - Removed "historical compatibility"
32+
-`gdscript.py` - Removed "was in original", "Fixed"
33+
-`ttcn.py` - Removed "was in original"
34+
-`st.py` - Removed "were missing from original"
35+
-`r.py` - Removed "Decision" language
36+
-`code_reader.py` - Simplified to current state
37+
-`lizardnonstrict.py` - Removed "instead of hardcoded"
38+
39+
### Test Comments Cleaned
40+
All test docstrings updated to current state:
41+
-`testGDScript.py` - Renamed test, removed "BUG", "Fixed"
42+
-`testSt.py` - Removed "BUG", "Bug fixed"
43+
-`testR.py` - Removed "BUG", renamed class
44+
-`testRust.py` - Removed "BUG", renamed test
45+
-`testErlang.py` - Removed "Decision", "NOTE"
46+
-`testTTCN.py` - Removed "BUG", renamed test
47+
48+
### Documentation Cleaned
49+
Only current-state documentation remains:
50+
```
51+
ongoing/
52+
├── checkstyle_output.md (unrelated feature)
53+
├── todo_list.md (current tasks only)
54+
├── language-implementation-guide.md (current state)
55+
├── condition-categories-reference.md (current state)
56+
├── code-structure-reference.md (current state)
57+
├── REFACTORING_COMPLETE.md (current status)
58+
└── VERIFICATION_COMPLETE.md (this file)
59+
```
60+
61+
Historical planning documents removed:
62+
-`separate-conditions-refactoring.md` (deleted)
63+
-`language-conditions-inventory.md` (deleted)
64+
-`conditions-problem-illustration.md` (deleted)
65+
-`conditions-refactoring-summary.md` (deleted)
66+
-`phase5-bugs-documented.md` (deleted)
67+
-`phase6-fixes-complete.md` (deleted)
68+
-`refactoring-complete-summary.md` (deleted)
69+
-`dead-code-review.md` (deleted)
70+
71+
## Test Results
72+
73+
```bash
74+
$ nix develop -c python -m pytest test/ -q --tb=no
75+
1021 passed, 6 skipped in 0.86s
76+
```
77+
78+
**All tests passing - 100% success rate**
79+
80+
## Summary
81+
82+
### Code State: ✅ Clean
83+
- No old `_conditions` definitions (except base compatibility)
84+
- All language readers use separated categories
85+
- All dead code removed
86+
87+
### Comments State: ✅ Current
88+
- No historical references ("was", "old", "before", "fixed", "bug")
89+
- All comments describe current state
90+
- Implementation rationale provided where needed
91+
92+
### Documentation State: ✅ Current
93+
- Only current-state guides remain
94+
- No historical planning documents
95+
- Clear reference material for contributors
96+
97+
### Test State: ✅ Passing
98+
- 1021 tests passing
99+
- Test names and docstrings reflect current behavior
100+
- No references to bugs or fixes in test descriptions
101+
102+
## Verification Complete ✅
103+
104+
**Confirmed**: All code, comments, and documentation reflect only the current state. No historical references remain.
105+

ongoing/code-structure-reference.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -204,22 +204,22 @@ All are mutable sets that extensions can modify.
204204

205205
## Backward Compatibility
206206

207-
The base class supports old-style `_conditions`:
207+
The base class supports two approaches for defining conditions:
208208

209209
```python
210-
# Old style (still supported):
211-
class OldReader(CodeReader):
212-
_conditions = {'if', 'for', '&&', '||', 'case', '?'} # Mixed
210+
# Approach 1: Define _conditions directly (for compatibility)
211+
class CustomReader(CodeReader):
212+
_conditions = {'if', 'for', '&&', '||', 'case', '?'} # Combined set
213213

214-
# New style (recommended):
215-
class NewReader(CodeReader):
214+
# Approach 2: Use separated categories (recommended)
215+
class ModernReader(CodeReader):
216216
_control_flow_keywords = {'if', 'for'}
217217
_logical_operators = {'&&', '||'}
218218
_case_keywords = {'case'}
219219
_ternary_operators = {'?'}
220220
```
221221

222-
Both work identically. The new style provides better semantics.
222+
Both approaches work identically. Separated categories provide better semantics and enable extensions to target specific types.
223223

224224
## Quick Reference Table
225225

0 commit comments

Comments
 (0)