lizard 1.17.28__py2.py3-none-any.whl → 1.17.29__py2.py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lizard
3
- Version: 1.17.28
3
+ Version: 1.17.29
4
4
  Summary: A code analyzer without caring the C/C++ header files. It works with Java, C/C++, JavaScript, Python, Ruby, Swift, Objective C. Metrics includes cyclomatic complexity number etc.
5
5
  Home-page: http://www.lizard.ws
6
6
  Download-URL: https://pypi.python.org/lizard/
@@ -25,7 +25,7 @@ lizard_ext/lizardns.py,sha256=8pztUoRS_UWN24MawwxeHEJgYh49id5PWODUBb6O72U,4184
25
25
  lizard_ext/lizardoutside.py,sha256=FGm2tbBZ17-2OCgmQlD-vobUCfQKb0FAygf86eM3xuM,336
26
26
  lizard_ext/lizardstatementcount.py,sha256=xYk6ixSIItSE1BWQXzrWmduFgGhA3VR817SNKLffyVQ,1182
27
27
  lizard_ext/lizardwordcount.py,sha256=2QYXD7-AtkkgAbi9VSidunMbSsGQ7MKYb6IT-bS-cok,7575
28
- lizard_ext/version.py,sha256=MvEnDbdl2cyQNZKMkfgQ5II9EbD6v9D0HTDqEiwL7T0,182
28
+ lizard_ext/version.py,sha256=QVDZyG9GV7lwS_Xtimsh3RbooOAR53x-mhgHy51HIjk,182
29
29
  lizard_ext/xmloutput.py,sha256=-cbh0he4O_X-wX56gkv9AnSPNN0qvR7FACqlBeezUS4,5609
30
30
  lizard_languages/__init__.py,sha256=ArNmUrVSU6HFxhDka1-vWMZpVIM39P-gqv6BoOLNMV8,1522
31
31
  lizard_languages/clike.py,sha256=INd5tkvwEVZm7dx2yHG2OIFHZn7JzQGmnT9WQNFZ2XU,11110
@@ -45,7 +45,7 @@ lizard_languages/kotlin.py,sha256=v_o2orEzA5gB9vM_0h-E4QXjrc5Yum-0K6W6_laOThc,28
45
45
  lizard_languages/lua.py,sha256=3nqBcunBzJrhv4Iqaf8xvbyqxZy3aSxJ-IiHimHFlac,1573
46
46
  lizard_languages/objc.py,sha256=2a1teLdaXZBtCeFiIZer1j_sVx9LZ1CbF2XfnqlvLmk,2319
47
47
  lizard_languages/perl.py,sha256=WUHuO9lIBRpL0fJKpAtEVsEatGMqzY2WymF8kSdPGRs,12143
48
- lizard_languages/php.py,sha256=8OufyR2TIWyf3bXuTmp37Vwf_tEPF4YV5M3i5_jnguA,1377
48
+ lizard_languages/php.py,sha256=gAI-UZckwjOKJ7HbINWS5w5iYsNRVyONb092dAsRLhs,10096
49
49
  lizard_languages/python.py,sha256=1e0dKbl82z-i_5dswkKaFIV5WuQDKztPHh9UNmSTLyE,3848
50
50
  lizard_languages/ruby.py,sha256=HL1ZckeuUUJU3QSVAOPsG_Zsl0C6X2PX5_VaWqclzkM,2277
51
51
  lizard_languages/rubylike.py,sha256=dAGZ2wqW8nqaESMU8HkeR9gwQ-q9fmZqE6AANvVZD1Q,3426
@@ -60,9 +60,9 @@ lizard_languages/ttcn.py,sha256=ygjw_raBmPF-4mgoM8m6CAdyEMpTI-n1kZJK1RL4Vxo,2131
60
60
  lizard_languages/typescript.py,sha256=P_rphg5AXJAk9QetmvVKc2911ilPmiRa0Qa5fHWleJg,3829
61
61
  lizard_languages/vue.py,sha256=KXUBUo2R1zNF8Pffrz_KsQEN44m5XFRMoGXylxKUeT0,1038
62
62
  lizard_languages/zig.py,sha256=NX1iyBstBuJFeAGBOAIaRfrmeBREne2HX6Pt4fXZZTQ,586
63
- lizard-1.17.28.dist-info/LICENSE.txt,sha256=05ZjgQ8Cl1dD9p0BhW-Txzkc5rhCogGJVEuf1GT2Y_M,1303
64
- lizard-1.17.28.dist-info/METADATA,sha256=gKFStxGqZyN-fZHhqraSEt6NPytI7bCgb4JnKf_Ix4Q,16130
65
- lizard-1.17.28.dist-info/WHEEL,sha256=Kh9pAotZVRFj97E15yTA4iADqXdQfIVTHcNaZTjxeGM,110
66
- lizard-1.17.28.dist-info/entry_points.txt,sha256=ZBqPhu-J3NoGGW5vn2Gfyoo0vdVlgBgM-wlNm0SGYUQ,39
67
- lizard-1.17.28.dist-info/top_level.txt,sha256=5NTrTaOLhHuTzXaGcZPKfuaOgUv7WafNGe0Zl5aycpg,35
68
- lizard-1.17.28.dist-info/RECORD,,
63
+ lizard-1.17.29.dist-info/LICENSE.txt,sha256=05ZjgQ8Cl1dD9p0BhW-Txzkc5rhCogGJVEuf1GT2Y_M,1303
64
+ lizard-1.17.29.dist-info/METADATA,sha256=ZhoBV3shfqxrAcPAQgNRdyMHnTrkQdON2PEY5owuMGo,16130
65
+ lizard-1.17.29.dist-info/WHEEL,sha256=Kh9pAotZVRFj97E15yTA4iADqXdQfIVTHcNaZTjxeGM,110
66
+ lizard-1.17.29.dist-info/entry_points.txt,sha256=ZBqPhu-J3NoGGW5vn2Gfyoo0vdVlgBgM-wlNm0SGYUQ,39
67
+ lizard-1.17.29.dist-info/top_level.txt,sha256=5NTrTaOLhHuTzXaGcZPKfuaOgUv7WafNGe0Zl5aycpg,35
68
+ lizard-1.17.29.dist-info/RECORD,,
lizard_ext/version.py CHANGED
@@ -3,4 +3,4 @@
3
3
  #
4
4
  # pylint: disable=missing-docstring,invalid-name
5
5
 
6
- version = "1.17.28"
6
+ version = "1.17.29"
lizard_languages/php.py CHANGED
@@ -1,11 +1,229 @@
1
1
  '''
2
- Language parser for JavaScript
2
+ Language parser for PHP
3
3
  '''
4
4
 
5
5
  import re
6
- from .code_reader import CodeReader
6
+ from .code_reader import CodeReader, CodeStateMachine
7
7
  from .clike import CCppCommentsMixin
8
- from .js_style_language_states import JavaScriptStyleLanguageStates
8
+
9
+
10
+ class PHPLanguageStates(CodeStateMachine):
11
+ """
12
+ PHP-specific state machine that properly handles modern PHP syntax
13
+ including classes, visibility modifiers and return types.
14
+ """
15
+
16
+ def __init__(self, context):
17
+ super(PHPLanguageStates, self).__init__(context)
18
+ self.function_name = ''
19
+ self.class_name = None
20
+ self.trait_name = None
21
+ self.in_class = False
22
+ self.in_trait = False
23
+ self.bracket_level = 0
24
+ self.brace_level = 0
25
+ self.started_function = False
26
+ self.last_token = ''
27
+ self.last_tokens = ''
28
+ self.is_function_declaration = False
29
+ self.assignments = []
30
+ self.in_match = False
31
+ self.match_case_count = 0
32
+
33
+ def _state_global(self, token):
34
+ if token == 'class':
35
+ self._state = self._class_declaration
36
+ elif token == 'trait':
37
+ self._state = self._trait_declaration
38
+ elif token == 'function':
39
+ self.is_function_declaration = True
40
+ self._state = self._function_name
41
+ elif token == 'fn':
42
+ # Skip arrow functions (PHP 7.4+), don't treat them as full functions
43
+ pass
44
+ elif token == 'match':
45
+ self.in_match = True
46
+ self.match_case_count = 0
47
+ self.next(self._match_expression)
48
+ elif token in ('if', 'switch', 'for', 'foreach', 'while', 'catch'):
49
+ self.next(self._condition_expected)
50
+ elif token in ('public', 'private', 'protected', 'static'):
51
+ # Skip visibility modifiers
52
+ pass
53
+ elif token == '=>' and self.in_match:
54
+ # Count each case in a match expression
55
+ self.match_case_count += 1
56
+ elif token == '}' and self.in_match:
57
+ # End of match expression
58
+ self.in_match = False
59
+ # Add the match cases to complexity (subtract 1 because the 'match' keyword is already counted)
60
+ if self.match_case_count > 0:
61
+ for _ in range(self.match_case_count - 1):
62
+ self.context.add_condition()
63
+ self.match_case_count = 0
64
+ elif token == '=':
65
+ # Handle function assignment
66
+ self.function_name = self.last_tokens.strip()
67
+ self.assignments.append(self.function_name)
68
+ elif token == '{':
69
+ self.brace_level += 1
70
+ elif token == '}':
71
+ self.brace_level -= 1
72
+ if self.brace_level == 0:
73
+ if self.in_class:
74
+ self.in_class = False
75
+ self.class_name = None
76
+ if self.in_trait:
77
+ self.in_trait = False
78
+ self.trait_name = None
79
+
80
+ # Update tokens
81
+ self.last_token = token
82
+ if token not in [' ', '\t', '\n']:
83
+ if token not in ['=', ';', '{', '}', '(', ')', ',']:
84
+ self.last_tokens = token
85
+ elif token == '=' and self.last_tokens:
86
+ # Keep the last tokens for assignment
87
+ pass
88
+ else:
89
+ self.last_tokens = ''
90
+
91
+ def _trait_declaration(self, token):
92
+ if token and not token.isspace() and token not in ['{', '(']:
93
+ self.trait_name = token
94
+ self.in_trait = True
95
+ self._state = self._state_global
96
+ elif token == '{':
97
+ self.brace_level += 1
98
+ self._state = self._state_global
99
+
100
+ def _class_declaration(self, token):
101
+ if token and not token.isspace() and token not in ['{', '(', 'extends', 'implements']:
102
+ self.class_name = token
103
+ self.in_class = True
104
+ self._state = self._state_global
105
+ elif token == '{':
106
+ self.brace_level += 1
107
+ self._state = self._state_global
108
+
109
+ def _function_name(self, token):
110
+ if token and not token.isspace() and token != '(':
111
+ method_name = token
112
+ if self.in_class and self.class_name:
113
+ # In class, use ClassName::methodName format
114
+ long_name = f"{self.class_name}::{method_name}"
115
+ short_name = method_name # Store original name for compatibility with old tests
116
+ elif self.in_trait and self.trait_name:
117
+ # In trait, use TraitName::methodName format
118
+ long_name = f"{self.trait_name}::{method_name}"
119
+ short_name = method_name
120
+ else:
121
+ long_name = method_name
122
+ short_name = method_name
123
+ self.function_name = long_name
124
+ self._state = self._function_args
125
+ # Store original name for backward compatibility
126
+ self.short_function_name = short_name
127
+ elif token == '(':
128
+ # Anonymous function
129
+ if self.in_class:
130
+ self.function_name = f"{self.class_name}::(anonymous)"
131
+ elif self.in_trait:
132
+ self.function_name = f"{self.trait_name}::(anonymous)"
133
+ else:
134
+ if self.assignments and self.assignments[-1]:
135
+ self.function_name = self.assignments[-1]
136
+ self.assignments.pop()
137
+ else:
138
+ self.function_name = "(anonymous)"
139
+ self.bracket_level = 1
140
+ self._state = self._function_args_continue
141
+ self.context.push_new_function(self.function_name)
142
+ self.started_function = True
143
+
144
+ def _function_args(self, token):
145
+ if token == '(':
146
+ self.bracket_level = 1
147
+ # Compatibility handling for old tests
148
+ if self.in_class and self.class_name and not self.is_function_declaration:
149
+ self.context.push_new_function(self.short_function_name)
150
+ else:
151
+ self.context.push_new_function(self.function_name)
152
+ self.started_function = True
153
+ self._state = self._function_args_continue
154
+
155
+ def _function_args_continue(self, token):
156
+ if token == '(':
157
+ self.bracket_level += 1
158
+ elif token == ')':
159
+ self.bracket_level -= 1
160
+ if self.bracket_level == 0:
161
+ self._state = self._function_return_type_or_body
162
+ elif token.startswith('$'):
163
+ # Found a parameter (PHP parameters start with $)
164
+ if self.started_function:
165
+ # Make sure we count each parameter uniquely
166
+ self.context.add_to_long_function_name(" " + token)
167
+ self.context.parameter(token)
168
+
169
+ def _function_return_type_or_body(self, token):
170
+ if token == ':':
171
+ # Skip return type declaration
172
+ self._state = self._function_body_or_return_type
173
+ elif token == '{':
174
+ # Function body starts
175
+ self.brace_level += 1
176
+ self._state = self._function_body
177
+ elif token == ';':
178
+ # Handle forward declarations in interface
179
+ if self.started_function:
180
+ self.context.end_of_function()
181
+ self.started_function = False
182
+ self._state = self._state_global
183
+
184
+ def _function_body_or_return_type(self, token):
185
+ if token == '{':
186
+ # Found the function body opening after return type
187
+ self.brace_level += 1
188
+ self._state = self._function_body
189
+
190
+ def _function_body(self, token):
191
+ if token == '{':
192
+ self.brace_level += 1
193
+ elif token == '}':
194
+ self.brace_level -= 1
195
+ if self.brace_level == self.in_class: # Using in_class as boolean (0/1)
196
+ # End of function
197
+ if self.started_function:
198
+ self.context.end_of_function()
199
+ self.started_function = False
200
+ self._state = self._state_global
201
+
202
+ def _condition_expected(self, token):
203
+ if token == '(':
204
+ self.bracket_level = 1
205
+ self._state = self._condition_continue
206
+
207
+ def _condition_continue(self, token):
208
+ if token == '(':
209
+ self.bracket_level += 1
210
+ elif token == ')':
211
+ self.bracket_level -= 1
212
+ if self.bracket_level == 0:
213
+ self._state = self._state_global
214
+
215
+ def _match_expression(self, token):
216
+ if token == '(':
217
+ self.bracket_level = 1
218
+ self._state = self._match_expression_continue
219
+
220
+ def _match_expression_continue(self, token):
221
+ if token == '(':
222
+ self.bracket_level += 1
223
+ elif token == ')':
224
+ self.bracket_level -= 1
225
+ if self.bracket_level == 0:
226
+ self._state = self._state_global
9
227
 
10
228
 
11
229
  class PHPReader(CodeReader, CCppCommentsMixin):
@@ -13,8 +231,8 @@ class PHPReader(CodeReader, CCppCommentsMixin):
13
231
 
14
232
  ext = ['php']
15
233
  language_names = ['php']
16
- _conditions = set(['if', 'elseif', 'for', 'while', '&&', '||', '?',
17
- 'catch', 'case'])
234
+ _conditions = set(['if', 'elseif', 'for', 'foreach', 'while', '&&', '||', '?',
235
+ 'catch', 'case', 'match'])
18
236
 
19
237
  @staticmethod
20
238
  def generate_tokens(source_code, addition='', token_class=None):
@@ -36,4 +254,4 @@ class PHPReader(CodeReader, CCppCommentsMixin):
36
254
 
37
255
  def __init__(self, context):
38
256
  super(PHPReader, self).__init__(context)
39
- self.parallel_states = [JavaScriptStyleLanguageStates(context)]
257
+ self.parallel_states = [PHPLanguageStates(context)]