lizard 1.17.10__tar.gz → 1.17.13__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.
Files changed (94) hide show
  1. {lizard-1.17.10 → lizard-1.17.13}/PKG-INFO +9 -7
  2. {lizard-1.17.10 → lizard-1.17.13}/README.rst +4 -2
  3. {lizard-1.17.10 → lizard-1.17.13}/lizard.egg-info/PKG-INFO +9 -7
  4. {lizard-1.17.10 → lizard-1.17.13}/lizard.egg-info/SOURCES.txt +3 -0
  5. lizard-1.17.13/lizard.egg-info/requires.txt +1 -0
  6. {lizard-1.17.10 → lizard-1.17.13}/lizard.py +8 -3
  7. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/version.py +1 -1
  8. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/__init__.py +5 -1
  9. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/clike.py +2 -1
  10. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/code_reader.py +21 -3
  11. lizard-1.17.13/lizard_languages/erlang.py +112 -0
  12. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/fortran.py +4 -3
  13. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/golike.py +28 -2
  14. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/python.py +7 -0
  15. lizard-1.17.13/lizard_languages/solidity.py +22 -0
  16. {lizard-1.17.10 → lizard-1.17.13}/setup.py +5 -4
  17. {lizard-1.17.10 → lizard-1.17.13}/test/testLanguages.py +8 -1
  18. {lizard-1.17.10 → lizard-1.17.13}/test/testOutputCSV.py +2 -2
  19. {lizard-1.17.10 → lizard-1.17.13}/test/testOutputHTML.py +1 -2
  20. {lizard-1.17.10 → lizard-1.17.13}/LICENSE.txt +0 -0
  21. {lizard-1.17.10 → lizard-1.17.13}/lizard.egg-info/dependency_links.txt +0 -0
  22. {lizard-1.17.10 → lizard-1.17.13}/lizard.egg-info/entry_points.txt +0 -0
  23. {lizard-1.17.10 → lizard-1.17.13}/lizard.egg-info/top_level.txt +0 -0
  24. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/__init__.py +0 -0
  25. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/auto_open.py +0 -0
  26. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/csvoutput.py +0 -0
  27. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/default_ordered_dict.py +0 -0
  28. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/extension_base.py +0 -0
  29. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/htmloutput.py +0 -0
  30. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/keywords.py +0 -0
  31. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizardboolcount.py +0 -0
  32. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizardcomplextags.py +0 -0
  33. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizardcpre.py +0 -0
  34. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizarddependencycount.py +0 -0
  35. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizarddumpcomments.py +0 -0
  36. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizardduplicate.py +0 -0
  37. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizardduplicated_param_list.py +0 -0
  38. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizardexitcount.py +0 -0
  39. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizardgotocount.py +0 -0
  40. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizardignoreassert.py +0 -0
  41. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizardio.py +0 -0
  42. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizardmccabe.py +0 -0
  43. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizardmodified.py +0 -0
  44. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizardnd.py +0 -0
  45. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizardnonstrict.py +0 -0
  46. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizardns.py +0 -0
  47. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizardoutside.py +0 -0
  48. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizardstatementcount.py +0 -0
  49. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/lizardwordcount.py +0 -0
  50. {lizard-1.17.10 → lizard-1.17.13}/lizard_ext/xmloutput.py +0 -0
  51. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/csharp.py +0 -0
  52. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/gdscript.py +0 -0
  53. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/go.py +0 -0
  54. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/java.py +0 -0
  55. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/javascript.py +0 -0
  56. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/js_style_language_states.py +0 -0
  57. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/js_style_regex_expression.py +0 -0
  58. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/kotlin.py +0 -0
  59. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/lua.py +0 -0
  60. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/objc.py +0 -0
  61. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/php.py +0 -0
  62. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/ruby.py +0 -0
  63. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/rubylike.py +0 -0
  64. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/rust.py +0 -0
  65. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/scala.py +0 -0
  66. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/script_language.py +0 -0
  67. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/swift.py +0 -0
  68. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/tnsdl.py +0 -0
  69. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/ttcn.py +0 -0
  70. {lizard-1.17.10 → lizard-1.17.13}/lizard_languages/typescript.py +0 -0
  71. {lizard-1.17.10 → lizard-1.17.13}/setup.cfg +0 -0
  72. {lizard-1.17.10 → lizard-1.17.13}/test/testApplication.py +0 -0
  73. {lizard-1.17.10 → lizard-1.17.13}/test/testAssertionExtension.py +0 -0
  74. {lizard-1.17.10 → lizard-1.17.13}/test/testBasicFunctionInfo.py +0 -0
  75. {lizard-1.17.10 → lizard-1.17.13}/test/testCOutsideComplexity.py +0 -0
  76. {lizard-1.17.10 → lizard-1.17.13}/test/testCPreprocessorExtension.py +0 -0
  77. {lizard-1.17.10 → lizard-1.17.13}/test/testCommentOptions.py +0 -0
  78. {lizard-1.17.10 → lizard-1.17.13}/test/testCyclomaticComplexity.py +0 -0
  79. {lizard-1.17.10 → lizard-1.17.13}/test/testExtension.py +0 -0
  80. {lizard-1.17.10 → lizard-1.17.13}/test/testFilesFilter.py +0 -0
  81. {lizard-1.17.10 → lizard-1.17.13}/test/testFunctionDependencyCount.py +0 -0
  82. {lizard-1.17.10 → lizard-1.17.13}/test/testFunctionExitCount.py +0 -0
  83. {lizard-1.17.10 → lizard-1.17.13}/test/testFunctionGotoCount.py +0 -0
  84. {lizard-1.17.10 → lizard-1.17.13}/test/testFunctionStatementCount.py +0 -0
  85. {lizard-1.17.10 → lizard-1.17.13}/test/testHelpers.py +0 -0
  86. {lizard-1.17.10 → lizard-1.17.13}/test/testMcCabe.py +0 -0
  87. {lizard-1.17.10 → lizard-1.17.13}/test/testNestedStructures.py +0 -0
  88. {lizard-1.17.10 → lizard-1.17.13}/test/testNestingDepth.py +0 -0
  89. {lizard-1.17.10 → lizard-1.17.13}/test/testOutput.py +0 -0
  90. {lizard-1.17.10 → lizard-1.17.13}/test/testOutputFile.py +0 -0
  91. {lizard-1.17.10 → lizard-1.17.13}/test/testTokenizer.py +0 -0
  92. {lizard-1.17.10 → lizard-1.17.13}/test/test_analyzer.py +0 -0
  93. {lizard-1.17.10 → lizard-1.17.13}/test/test_auto_open.py +0 -0
  94. {lizard-1.17.10 → lizard-1.17.13}/test/test_options.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lizard
3
- Version: 1.17.10
3
+ Version: 1.17.13
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/
@@ -23,10 +23,10 @@ Classifier: Programming Language :: Java
23
23
  Classifier: Programming Language :: JavaScript
24
24
  Classifier: Programming Language :: Objective C
25
25
  Classifier: Programming Language :: Python
26
- Classifier: Programming Language :: Python :: 2.7
27
- Classifier: Programming Language :: Python :: 3.4
28
- Classifier: Programming Language :: Python :: 3.5
29
- Classifier: Programming Language :: Python :: 3.6
26
+ Classifier: Programming Language :: Python :: 3.8
27
+ Classifier: Programming Language :: Python :: 3.9
28
+ Classifier: Programming Language :: Python :: 3.10
29
+ Classifier: Programming Language :: Python :: 3.11
30
30
  License-File: LICENSE.txt
31
31
 
32
32
  |Web Site| Lizard
@@ -66,6 +66,8 @@ A list of supported languages:
66
66
  - Rust
67
67
  - Fortran
68
68
  - Kotlin
69
+ - Solidity
70
+ - Erlang
69
71
 
70
72
  By default lizard will search for any source code that it knows and mix
71
73
  all the results together. This might not be what you want. You can use
@@ -88,7 +90,7 @@ often very hard to get all the included folders and files right when
88
90
  they are complicated. But we don't really need that kind of accuracy for
89
91
  cyclomatic complexity.
90
92
 
91
- It requires python2.7 or above (early versions are not verified).
93
+ It requires python3.8 or above (early versions are not verified).
92
94
 
93
95
  Installation
94
96
  ------------
@@ -112,7 +114,7 @@ Or if you've got the source:
112
114
 
113
115
  ::
114
116
 
115
- [sudo] python setup.py install --install-dir=/path/to/installation/directory/
117
+ [sudo] python setup.py install --prefix=/path/to/installation/directory/
116
118
 
117
119
  Usage
118
120
  -----
@@ -35,6 +35,8 @@ A list of supported languages:
35
35
  - Rust
36
36
  - Fortran
37
37
  - Kotlin
38
+ - Solidity
39
+ - Erlang
38
40
 
39
41
  By default lizard will search for any source code that it knows and mix
40
42
  all the results together. This might not be what you want. You can use
@@ -57,7 +59,7 @@ often very hard to get all the included folders and files right when
57
59
  they are complicated. But we don't really need that kind of accuracy for
58
60
  cyclomatic complexity.
59
61
 
60
- It requires python2.7 or above (early versions are not verified).
62
+ It requires python3.8 or above (early versions are not verified).
61
63
 
62
64
  Installation
63
65
  ------------
@@ -81,7 +83,7 @@ Or if you've got the source:
81
83
 
82
84
  ::
83
85
 
84
- [sudo] python setup.py install --install-dir=/path/to/installation/directory/
86
+ [sudo] python setup.py install --prefix=/path/to/installation/directory/
85
87
 
86
88
  Usage
87
89
  -----
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lizard
3
- Version: 1.17.10
3
+ Version: 1.17.13
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/
@@ -23,10 +23,10 @@ Classifier: Programming Language :: Java
23
23
  Classifier: Programming Language :: JavaScript
24
24
  Classifier: Programming Language :: Objective C
25
25
  Classifier: Programming Language :: Python
26
- Classifier: Programming Language :: Python :: 2.7
27
- Classifier: Programming Language :: Python :: 3.4
28
- Classifier: Programming Language :: Python :: 3.5
29
- Classifier: Programming Language :: Python :: 3.6
26
+ Classifier: Programming Language :: Python :: 3.8
27
+ Classifier: Programming Language :: Python :: 3.9
28
+ Classifier: Programming Language :: Python :: 3.10
29
+ Classifier: Programming Language :: Python :: 3.11
30
30
  License-File: LICENSE.txt
31
31
 
32
32
  |Web Site| Lizard
@@ -66,6 +66,8 @@ A list of supported languages:
66
66
  - Rust
67
67
  - Fortran
68
68
  - Kotlin
69
+ - Solidity
70
+ - Erlang
69
71
 
70
72
  By default lizard will search for any source code that it knows and mix
71
73
  all the results together. This might not be what you want. You can use
@@ -88,7 +90,7 @@ often very hard to get all the included folders and files right when
88
90
  they are complicated. But we don't really need that kind of accuracy for
89
91
  cyclomatic complexity.
90
92
 
91
- It requires python2.7 or above (early versions are not verified).
93
+ It requires python3.8 or above (early versions are not verified).
92
94
 
93
95
  Installation
94
96
  ------------
@@ -112,7 +114,7 @@ Or if you've got the source:
112
114
 
113
115
  ::
114
116
 
115
- [sudo] python setup.py install --install-dir=/path/to/installation/directory/
117
+ [sudo] python setup.py install --prefix=/path/to/installation/directory/
116
118
 
117
119
  Usage
118
120
  -----
@@ -7,6 +7,7 @@ lizard.egg-info/PKG-INFO
7
7
  lizard.egg-info/SOURCES.txt
8
8
  lizard.egg-info/dependency_links.txt
9
9
  lizard.egg-info/entry_points.txt
10
+ lizard.egg-info/requires.txt
10
11
  lizard.egg-info/top_level.txt
11
12
  lizard_ext/__init__.py
12
13
  lizard_ext/auto_open.py
@@ -40,6 +41,7 @@ lizard_languages/__init__.py
40
41
  lizard_languages/clike.py
41
42
  lizard_languages/code_reader.py
42
43
  lizard_languages/csharp.py
44
+ lizard_languages/erlang.py
43
45
  lizard_languages/fortran.py
44
46
  lizard_languages/gdscript.py
45
47
  lizard_languages/go.py
@@ -58,6 +60,7 @@ lizard_languages/rubylike.py
58
60
  lizard_languages/rust.py
59
61
  lizard_languages/scala.py
60
62
  lizard_languages/script_language.py
63
+ lizard_languages/solidity.py
61
64
  lizard_languages/swift.py
62
65
  lizard_languages/tnsdl.py
63
66
  lizard_languages/ttcn.py
@@ -0,0 +1 @@
1
+ pygments
@@ -301,11 +301,17 @@ class FunctionInfo(Nesting): # pylint: disable=R0902
301
301
  " %(name)s@%(start_line)s-%(end_line)s@%(filename)s"
302
302
  % self.__dict__)
303
303
 
304
- parameter_count = property(lambda self: len(self.full_parameters))
304
+ parameter_count = property(lambda self: len(self.parameters))
305
305
 
306
306
  @property
307
307
  def parameters(self):
308
- matches = [re.search(r'(\w+)(\s=.*)?$', f)
308
+ # Exclude empty tokens as parameters. These can occur in languages
309
+ # allowing a trailing comma on the last parameter in an function
310
+ # argument list.
311
+ # Regex matches the parameter name, then optionally:
312
+ # - a default value given after an '=' sign
313
+ # - a type annotation given after a ':'
314
+ matches = [re.search(r'(\w+)(\s=.*)?(\s:.*)?$', f)
309
315
  for f in self.full_parameters]
310
316
  return [m.group(1) for m in matches if m]
311
317
 
@@ -364,7 +370,6 @@ class NestingStack(object):
364
370
  def __init__(self):
365
371
  self.nesting_stack = []
366
372
  self.pending_function = None
367
- self.function_stack = []
368
373
 
369
374
  def with_namespace(self, name):
370
375
  return ''.join([x.name_in_space for x in self.nesting_stack] + [name])
@@ -3,4 +3,4 @@
3
3
  #
4
4
  # pylint: disable=missing-docstring,invalid-name
5
5
 
6
- version = "1.17.10"
6
+ version = "1.17.13"
@@ -1,6 +1,7 @@
1
1
  ''' programming languages of lizard '''
2
2
 
3
3
  from .clike import CLikeReader
4
+ from .erlang import ErlangReader
4
5
  from .java import JavaReader
5
6
  from .javascript import JavaScriptReader
6
7
  from .kotlin import KotlinReader
@@ -18,6 +19,7 @@ from .lua import LuaReader
18
19
  from .rust import RustReader
19
20
  from .typescript import TypeScriptReader
20
21
  from .fortran import FortranReader
22
+ from .solidity import SolidityReader
21
23
 
22
24
 
23
25
  def languages():
@@ -39,7 +41,9 @@ def languages():
39
41
  RustReader,
40
42
  TypeScriptReader,
41
43
  FortranReader,
42
- KotlinReader
44
+ KotlinReader,
45
+ SolidityReader,
46
+ ErlangReader,
43
47
  ]
44
48
 
45
49
 
@@ -196,7 +196,8 @@ class CLikeStates(CodeStateMachine):
196
196
  else:
197
197
  self.next(self._state_global)
198
198
  elif len(self.bracket_stack) == 1:
199
- self.context.parameter(token)
199
+ if token != 'void': # void is a reserved keyword, meaning no parameters
200
+ self.context.parameter(token)
200
201
  return
201
202
  self.context.add_to_long_function_name(token)
202
203
 
@@ -4,6 +4,8 @@ Base class for all language parsers
4
4
 
5
5
  import re
6
6
  from copy import copy
7
+ from functools import reduce
8
+ from operator import or_
7
9
 
8
10
 
9
11
  class CodeStateMachine(object):
@@ -112,7 +114,7 @@ class CodeReader:
112
114
  if not token_class:
113
115
  token_class = create_token
114
116
 
115
- def _generate_tokens(source, add):
117
+ def _generate_tokens(source, add, flags=0):
116
118
  # DO NOT put any sub groups in the regex. Good for performance
117
119
  _until_end = r"(?:\\\n|[^\n])*"
118
120
  combined_symbols = ["<<=", ">>=", "||", "&&", "===", "!==",
@@ -125,6 +127,8 @@ class CodeReader:
125
127
  r"\/\*.*?\*\/" +
126
128
  add +
127
129
  r"|(?:\d+\')+\d+" +
130
+ r"|0x(?:[0-9A-Fa-f]+\')+[0-9A-Fa-f]+" +
131
+ r"|0b(?:[01]+\')+[01]+" +
128
132
  r"|\w+" +
129
133
  r"|\"(?:\\.|[^\"\\])*\"" +
130
134
  r"|\'(?:\\.|[^\'\\])*?\'" +
@@ -136,7 +140,7 @@ class CodeReader:
136
140
  r"|\\\n" +
137
141
  r"|\n" +
138
142
  r"|[^\S\n]+" +
139
- r"|.)", re.M | re.S)
143
+ r"|.)", re.M | re.S | flags)
140
144
  macro = ""
141
145
  for match in token_pattern.finditer(source):
142
146
  token = token_class(match)
@@ -154,7 +158,21 @@ class CodeReader:
154
158
  if macro:
155
159
  yield macro
156
160
 
157
- return _generate_tokens(source_code, addition)
161
+ flag_dict = {
162
+ 'a': re.A, # ASCII-only matching
163
+ 'i': re.I, # Ignore case
164
+ 'L': re.L, # Locale dependent
165
+ 'm': re.M, # Multi-line
166
+ 's': re.S, # Dot matches all
167
+ 'u': re.U, # Unicode matching
168
+ 'x': re.X # Verbose
169
+ }
170
+
171
+ pattern = re.compile(r'\(\?[aiLmsux]+\)')
172
+ re_flags = ''.join(opt[2:-1] for opt in pattern.findall(addition))
173
+ flags = reduce(or_, (flag_dict[flag] for flag in re_flags), 0)
174
+
175
+ return _generate_tokens(source_code, pattern.sub('', addition), flags=flags)
158
176
 
159
177
  def __call__(self, tokens, reader):
160
178
  self.context = reader.context
@@ -0,0 +1,112 @@
1
+ """
2
+ Language parser for erlang
3
+ """
4
+
5
+ import re
6
+ from lizard_languages.code_reader import CodeReader, CodeStateMachine
7
+ import pygments.token as py_token
8
+ from pygments import lex, lexers
9
+
10
+
11
+ class ErlangReader(CodeReader):
12
+ # pylint: disable=R0903
13
+
14
+ ext = ['erl', 'hrl', 'es', 'escript']
15
+ language_names = ['erlang']
16
+ _conditions = {'and', 'case', 'catch', 'if', 'not', 'or', '?', 'when'}
17
+
18
+ def __init__(self, context):
19
+ super(ErlangReader, self).__init__(context)
20
+ self.parallel_states = [ErlangStates(context)]
21
+
22
+ @staticmethod
23
+ def get_comment_from_token(token):
24
+ if token.startswith("%%"):
25
+ return token[2:]
26
+
27
+ @staticmethod
28
+ def generate_tokens(source_code, addition='', token_class=None):
29
+ return map(lambda x: x[1], filter(lambda x: x[0] != py_token.Whitespace,
30
+ lex(source_code, lexer=lexers.get_lexer_by_name('erlang'))))
31
+
32
+
33
+ class ErlangStates(CodeStateMachine):
34
+ # pylint: disable=R0903
35
+
36
+ func_name_pattern = re.compile("[a-zA-Z]+[a-zA-Z0-9_]*")
37
+
38
+ def __init__(self, context):
39
+ super(ErlangStates, self).__init__(context)
40
+ self.punctuated = False
41
+
42
+ def _state_global(self, token):
43
+ if token == '-':
44
+ self.punctuated = True
45
+ elif self.func_name_pattern.match(token) and not self.punctuated:
46
+ self.context.push_new_function(token)
47
+ self._state = self._state_after_name
48
+ elif token == 'end':
49
+ self._state = self._state_nested_end
50
+ elif token == '.' or token == ';':
51
+ self.statemachine_return()
52
+ else:
53
+ self.punctuated = False
54
+
55
+ def _state_after_name(self, token):
56
+ if token == '(':
57
+ self._state = self._state_start_of_params
58
+ self.context.add_to_long_function_name(token)
59
+ self.lbr = 1
60
+ self.rbr = 0
61
+ else:
62
+ self.func_match_failed(token)
63
+
64
+ def _state_start_of_params(self, token):
65
+ if token == ')':
66
+ self.rbr += 1
67
+ if self.lbr == self.rbr:
68
+ self._state = self._state_end_of_params
69
+ self.context.add_to_long_function_name(" " + token)
70
+ self.punctuated = False
71
+ return
72
+ if token == '(':
73
+ self.lbr += 1
74
+ self.context.parameter(token)
75
+
76
+ def _state_end_of_params(self, token):
77
+ if token == '-':
78
+ self.punctuated = True
79
+ elif token == '>' and self.punctuated:
80
+ if len(self.context.stacked_functions) <= 1 or \
81
+ self.context.current_function.name == 'fun':
82
+ self.next(self._state_func_first_line, token)
83
+ else:
84
+ self.func_match_failed(token)
85
+
86
+ def _state_func_first_line(self, _):
87
+ def callback():
88
+ self._state = self._state_global
89
+ self.context.end_of_function()
90
+
91
+ self.sub_state(self.statemachine_clone(), callback)
92
+ self.punctuated = False
93
+
94
+ def _state_nested_end(self, token):
95
+ if token == '.' or token == ',':
96
+ if len(self.context.stacked_functions) > 1 \
97
+ and self.context.stacked_functions[-1].name == 'fun':
98
+ self.statemachine_return()
99
+ return
100
+
101
+ self._state = self._state_global
102
+
103
+ def func_match_failed(self, token):
104
+ self.punctuated = False
105
+ self._state = self._state_global
106
+ curr_cyc_comp = self.context.current_function.cyclomatic_complexity - 1
107
+ if self.context.stacked_functions:
108
+ self.context.current_function = self.context.stacked_functions.pop()
109
+ else:
110
+ self.context.current_function = self.context.global_pseudo_function
111
+ self.context.add_condition(curr_cyc_comp)
112
+ self.next(self._state_global, token)
@@ -35,11 +35,10 @@ class FortranReader(CodeReader, FortranCommentsMixin):
35
35
  _until_end = r'(?:\\\n|[^\n])*'
36
36
  return CodeReader.generate_tokens(
37
37
  source_code,
38
- r'(?i)' +
39
- r'|\/\/' +
38
+ r'(?i)'
39
+ r'\/\/' +
40
40
  r'|\#' + _until_end +
41
41
  r'|\!' + _until_end +
42
- r'|^C' + _until_end +
43
42
  r'|^\*' + _until_end +
44
43
  r'|\.OR\.' +
45
44
  r'|\.AND\.' +
@@ -124,6 +123,8 @@ class FortranStates(CodeStateMachine):
124
123
  self.context.add_bare_nesting()
125
124
  elif token_upper.replace(' ', '') == 'ELSEIF':
126
125
  self.context.pop_nesting()
126
+ if token_upper == 'ELSEIF':
127
+ self.context.add_condition()
127
128
  self._state = self._if
128
129
  elif token_upper == 'END' or self._ends.match(token):
129
130
  self.context.pop_nesting()
@@ -13,15 +13,40 @@ class GoLikeStates(CodeStateMachine): # pylint: disable=R0903
13
13
  if token == self.FUNC_KEYWORD:
14
14
  self._state = self._function_name
15
15
  self.context.push_new_function('')
16
+ elif token == 'type':
17
+ self._state = self._type_definition
16
18
  elif token in '{':
17
19
  self.sub_state(self.statemachine_clone())
18
20
  elif token in '}':
19
21
  self.statemachine_return()
20
22
 
23
+ def _type_definition(self, token):
24
+ self._state = self._after_type_name
25
+
26
+ def _after_type_name(self, token):
27
+ if token == 'struct':
28
+ self._state = self._struct_definition
29
+ elif token == 'interface':
30
+ self._state = self._interface_definition
31
+ else:
32
+ self._state = self._state_global
33
+
34
+ @CodeStateMachine.read_inside_brackets_then("{}", "_state_global")
35
+ def _struct_definition(self, tokens):
36
+ pass
37
+
38
+ @CodeStateMachine.read_inside_brackets_then("{}", "_state_global")
39
+ def _interface_definition(self, tokens):
40
+ pass
41
+
21
42
  def _function_name(self, token):
22
43
  if token != '`':
23
44
  if token == '(':
24
- return self.next(self._member_function, token)
45
+ if len(self.context.stacked_functions) > 0\
46
+ and self.context.stacked_functions[-1].name != '*global*':
47
+ return self.next(self._function_dec, token)
48
+ else:
49
+ return self.next(self._member_function, token)
25
50
  if token == '{':
26
51
  return self.next(self._expect_function_impl, token)
27
52
  self.context.add_to_function_name(token)
@@ -49,7 +74,8 @@ class GoLikeStates(CodeStateMachine): # pylint: disable=R0903
49
74
  self.context.parameter(token)
50
75
 
51
76
  def _expect_function_impl(self, token):
52
- self.next_if(self._function_impl, token, '{')
77
+ if token == '{' and self.last_token != 'interface':
78
+ self.next(self._function_impl, token)
53
79
 
54
80
  def _function_impl(self, _):
55
81
  def callback():
@@ -84,6 +84,8 @@ class PythonStates(CodeStateMachine): # pylint: disable=R0903
84
84
  def _dec(self, token):
85
85
  if token == ')':
86
86
  self._state = self._state_colon
87
+ elif token == '[':
88
+ self._state = self._state_parameterized_type_annotation
87
89
  else:
88
90
  self.context.parameter(token)
89
91
  return
@@ -100,3 +102,8 @@ class PythonStates(CodeStateMachine): # pylint: disable=R0903
100
102
  if token.startswith('"""') or token.startswith("'''"):
101
103
  self.context.add_nloc(-token.count('\n') - 1)
102
104
  self._state_global(token)
105
+
106
+ def _state_parameterized_type_annotation(self, token):
107
+ self.context.add_to_long_function_name(" " + token)
108
+ if token == ']':
109
+ self._state = self._dec
@@ -0,0 +1,22 @@
1
+ '''
2
+ Language parser for Solidity
3
+ '''
4
+
5
+ from .clike import CCppCommentsMixin
6
+ from .code_reader import CodeReader
7
+ from .golike import GoLikeStates
8
+
9
+
10
+ class SolidityReader(CodeReader, CCppCommentsMixin):
11
+
12
+ ext = ['sol']
13
+ language_names = ['solidity']
14
+ _conditions = set(['if', 'for', 'while', '&&', '||', '?'])
15
+
16
+ def __init__(self, context):
17
+ super(SolidityReader, self).__init__(context)
18
+ self.parallel_states = [SolidityStates(context)]
19
+
20
+
21
+ class SolidityStates(GoLikeStates): # pylint: disable=R0903
22
+ FUNC_KEYWORD = 'function'
@@ -87,14 +87,15 @@ setup(
87
87
  'Programming Language :: JavaScript',
88
88
  'Programming Language :: Objective C',
89
89
  'Programming Language :: Python',
90
- 'Programming Language :: Python :: 2.7',
91
- 'Programming Language :: Python :: 3.4',
92
- 'Programming Language :: Python :: 3.5',
93
- 'Programming Language :: Python :: 3.6'],
90
+ 'Programming Language :: Python :: 3.8',
91
+ 'Programming Language :: Python :: 3.9',
92
+ 'Programming Language :: Python :: 3.10',
93
+ 'Programming Language :: Python :: 3.11'],
94
94
  cmdclass={'version': VersionCommand},
95
95
  packages=['lizard_ext', 'lizard_languages'],
96
96
  #data_files=[('lizard_ext', [])],
97
97
  py_modules=['lizard'],
98
+ install_requires=['pygments'],
98
99
  entry_points={'console_scripts': ['lizard = lizard:main']},
99
100
  author='Terry Yin',
100
101
  author_email='terry@odd-e.com',
@@ -1,5 +1,6 @@
1
1
  import unittest
2
- from lizard_languages import get_reader_for, CLikeReader, JavaReader, ObjCReader, JavaScriptReader, ScalaReader, GDScriptReader
2
+ from lizard_languages import get_reader_for, CLikeReader, JavaReader, ObjCReader, JavaScriptReader, ScalaReader,\
3
+ GDScriptReader, SolidityReader, ErlangReader
3
4
 
4
5
 
5
6
  class TestLanguageChooser(unittest.TestCase):
@@ -29,3 +30,9 @@ class TestLanguageChooser(unittest.TestCase):
29
30
 
30
31
  def test_unknown_extension(self):
31
32
  self.assertEqual(None, get_reader_for("a.unknown"))
33
+
34
+ def test_Solidity(self):
35
+ self.assertEqual(SolidityReader, get_reader_for("a.sol"))
36
+
37
+ def test_erlang(self):
38
+ self.assertEqual(ErlangReader, get_reader_for("a.erl"))
@@ -22,7 +22,7 @@ class TestCSVOutput(StreamStdoutTestCase):
22
22
  options_mock.verbose = True
23
23
  options_mock.extensions = []
24
24
  csv_output(AllResult([self.fileSummary]), options_mock)
25
- self.assertRegexpMatches(sys.stdout.stream,
25
+ self.assertRegex(sys.stdout.stream,
26
26
  r"NLOC,CCN,token,PARAM,length,location,file,function,long_name,start,end")
27
27
 
28
28
  def test_csv_header_with_extension(self):
@@ -35,7 +35,7 @@ class TestCSVOutput(StreamStdoutTestCase):
35
35
  results = AllResult([self.fileSummary])
36
36
  results.result[0].function_list[0].exit_count = 1
37
37
  csv_output(results, options_mock)
38
- self.assertRegexpMatches(sys.stdout.stream,
38
+ self.assertRegex(sys.stdout.stream,
39
39
  r"NLOC,CCN,token,PARAM,length,location,file,function,long_name,start,end,exits")
40
40
 
41
41
  def test_csv_no_header(self):
@@ -17,6 +17,5 @@ class TestHTMLOutput(StreamStdoutTestCase):
17
17
 
18
18
  def test_should_have_html_body(self):
19
19
  html_output([self.fileSummary], self.option, None, AllResult)
20
- self.assertRegexpMatches(sys.stdout.stream,
21
- r"\<html\>")
20
+ self.assertRegex(sys.stdout.stream, r"\<html\>")
22
21
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes