lizard 1.17.19__tar.gz → 1.17.21__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.
- {lizard-1.17.19 → lizard-1.17.21}/PKG-INFO +2 -1
- {lizard-1.17.19 → lizard-1.17.21}/README.rst +1 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard.egg-info/PKG-INFO +2 -1
- {lizard-1.17.19 → lizard-1.17.21}/lizard.egg-info/SOURCES.txt +1 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/version.py +1 -1
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/__init__.py +2 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/java.py +0 -1
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/js_style_language_states.py +9 -1
- lizard-1.17.21/lizard_languages/jsx.py +265 -0
- lizard-1.17.21/lizard_languages/perl.py +103 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/tsx.py +11 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/typescript.py +6 -2
- lizard-1.17.19/lizard_languages/jsx.py +0 -141
- {lizard-1.17.19 → lizard-1.17.21}/LICENSE.txt +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard.egg-info/dependency_links.txt +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard.egg-info/entry_points.txt +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard.egg-info/requires.txt +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard.egg-info/top_level.txt +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/__init__.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/auto_open.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/csvoutput.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/default_ordered_dict.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/extension_base.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/htmloutput.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/keywords.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizardboolcount.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizardcomplextags.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizardcpre.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizarddependencycount.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizarddumpcomments.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizardduplicate.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizardduplicated_param_list.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizardexitcount.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizardgotocount.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizardignoreassert.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizardio.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizardmccabe.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizardmodified.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizardnd.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizardnonstrict.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizardns.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizardoutside.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizardstatementcount.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/lizardwordcount.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_ext/xmloutput.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/clike.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/code_reader.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/csharp.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/erlang.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/fortran.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/gdscript.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/go.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/golike.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/javascript.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/js_style_regex_expression.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/kotlin.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/lua.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/objc.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/php.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/python.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/ruby.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/rubylike.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/rust.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/scala.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/script_language.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/solidity.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/swift.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/tnsdl.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/ttcn.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/vue.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/lizard_languages/zig.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/setup.cfg +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/setup.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testApplication.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testAssertionExtension.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testBasicFunctionInfo.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testCOutsideComplexity.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testCPreprocessorExtension.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testCommentOptions.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testCyclomaticComplexity.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testExtension.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testFilesFilter.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testFunctionDependencyCount.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testFunctionExitCount.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testFunctionGotoCount.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testFunctionStatementCount.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testHelpers.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testLanguages.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testMcCabe.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testNestedStructures.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testNestingDepth.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testOutput.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testOutputCSV.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testOutputFile.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testOutputHTML.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/testTokenizer.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/test_analyzer.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/test_auto_open.py +0 -0
- {lizard-1.17.19 → lizard-1.17.21}/test/test_options.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lizard
|
|
3
|
-
Version: 1.17.
|
|
3
|
+
Version: 1.17.21
|
|
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/
|
|
@@ -70,6 +70,7 @@ A list of supported languages:
|
|
|
70
70
|
- Solidity
|
|
71
71
|
- Erlang
|
|
72
72
|
- Zig
|
|
73
|
+
- Perl
|
|
73
74
|
|
|
74
75
|
By default lizard will search for any source code that it knows and mix
|
|
75
76
|
all the results together. This might not be what you want. You can use
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lizard
|
|
3
|
-
Version: 1.17.
|
|
3
|
+
Version: 1.17.21
|
|
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/
|
|
@@ -70,6 +70,7 @@ A list of supported languages:
|
|
|
70
70
|
- Solidity
|
|
71
71
|
- Erlang
|
|
72
72
|
- Zig
|
|
73
|
+
- Perl
|
|
73
74
|
|
|
74
75
|
By default lizard will search for any source code that it knows and mix
|
|
75
76
|
all the results together. This might not be what you want. You can use
|
|
@@ -24,6 +24,7 @@ from .solidity import SolidityReader
|
|
|
24
24
|
from .jsx import JSXReader
|
|
25
25
|
from .tsx import TSXReader
|
|
26
26
|
from .vue import VueReader
|
|
27
|
+
from .perl import PerlReader
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
def languages():
|
|
@@ -52,6 +53,7 @@ def languages():
|
|
|
52
53
|
JSXReader,
|
|
53
54
|
TSXReader,
|
|
54
55
|
VueReader,
|
|
56
|
+
PerlReader,
|
|
55
57
|
]
|
|
56
58
|
|
|
57
59
|
|
|
@@ -34,6 +34,8 @@ class JavaScriptStyleLanguageStates(CodeStateMachine): # pylint: disable=R0903
|
|
|
34
34
|
elif token in ('else', 'do', 'try', 'final'):
|
|
35
35
|
self.next(self._expecting_statement_or_block)
|
|
36
36
|
elif token in ('=>',):
|
|
37
|
+
if self.function_name:
|
|
38
|
+
self._push_function_to_stack()
|
|
37
39
|
self._state = self._arrow_function
|
|
38
40
|
elif token == '=':
|
|
39
41
|
self.function_name = self.last_tokens
|
|
@@ -100,7 +102,13 @@ class JavaScriptStyleLanguageStates(CodeStateMachine): # pylint: disable=R0903
|
|
|
100
102
|
|
|
101
103
|
def _arrow_function(self, token):
|
|
102
104
|
self._push_function_to_stack()
|
|
103
|
-
|
|
105
|
+
# Handle arrow function body
|
|
106
|
+
if token == '{':
|
|
107
|
+
# Block body
|
|
108
|
+
self.next(self._state_global, token)
|
|
109
|
+
else:
|
|
110
|
+
# Expression body
|
|
111
|
+
self.next(self._state_global, token)
|
|
104
112
|
|
|
105
113
|
def _function(self, token):
|
|
106
114
|
if token == '*':
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Language parser for JSX
|
|
3
|
+
'''
|
|
4
|
+
|
|
5
|
+
from .javascript import JavaScriptReader
|
|
6
|
+
from .typescript import JSTokenizer, Tokenizer
|
|
7
|
+
from .code_reader import CodeReader
|
|
8
|
+
from .js_style_regex_expression import js_style_regex_expression
|
|
9
|
+
from .js_style_language_states import JavaScriptStyleLanguageStates
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TSXTokenizer(JSTokenizer):
|
|
13
|
+
def __init__(self):
|
|
14
|
+
super().__init__()
|
|
15
|
+
|
|
16
|
+
def process_token(self, token):
|
|
17
|
+
if token == "<":
|
|
18
|
+
from .jsx import XMLTagWithAttrTokenizer # Import only when needed
|
|
19
|
+
self.sub_tokenizer = XMLTagWithAttrTokenizer()
|
|
20
|
+
return
|
|
21
|
+
|
|
22
|
+
if token == "=>":
|
|
23
|
+
# Special handling for arrow functions
|
|
24
|
+
yield token
|
|
25
|
+
return
|
|
26
|
+
|
|
27
|
+
for tok in super().process_token(token):
|
|
28
|
+
yield tok
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class JSXMixin:
|
|
32
|
+
'''Base mixin class for JSX/TSX shared functionality'''
|
|
33
|
+
@staticmethod
|
|
34
|
+
@js_style_regex_expression
|
|
35
|
+
def generate_tokens(source_code, addition='', token_class=None):
|
|
36
|
+
addition = addition +\
|
|
37
|
+
r"|(?:\$\w+)" + \
|
|
38
|
+
r"|(?:\<\/\w+\>)" + \
|
|
39
|
+
r"|(?:=>)" + \
|
|
40
|
+
r"|`.*?`"
|
|
41
|
+
js_tokenizer = TSXTokenizer()
|
|
42
|
+
for token in CodeReader.generate_tokens(
|
|
43
|
+
source_code, addition, token_class):
|
|
44
|
+
for tok in js_tokenizer(token):
|
|
45
|
+
yield tok
|
|
46
|
+
|
|
47
|
+
def _expecting_func_opening_bracket(self, token):
|
|
48
|
+
if token == '<':
|
|
49
|
+
self.next(self._expecting_jsx)
|
|
50
|
+
return
|
|
51
|
+
if token == '=>':
|
|
52
|
+
# Handle arrow functions in JSX attributes
|
|
53
|
+
self._handle_arrow_function()
|
|
54
|
+
return
|
|
55
|
+
super()._expecting_func_opening_bracket(token)
|
|
56
|
+
|
|
57
|
+
def _handle_arrow_function(self):
|
|
58
|
+
# Process arrow function in JSX context
|
|
59
|
+
self.context.add_to_long_function_name(" => ")
|
|
60
|
+
|
|
61
|
+
# Store the current function
|
|
62
|
+
current_function = self.context.current_function
|
|
63
|
+
|
|
64
|
+
# Create a new anonymous function
|
|
65
|
+
self.context.restart_new_function('(anonymous)')
|
|
66
|
+
|
|
67
|
+
# Set up for the arrow function body
|
|
68
|
+
def callback():
|
|
69
|
+
# Return to the original function when done
|
|
70
|
+
self.context.current_function = current_function
|
|
71
|
+
|
|
72
|
+
self.sub_state(self.__class__(self.context), callback)
|
|
73
|
+
|
|
74
|
+
def _expecting_arrow_function_body(self, token):
|
|
75
|
+
if token == '{':
|
|
76
|
+
# Arrow function with block body
|
|
77
|
+
self.next(self._function_body)
|
|
78
|
+
else:
|
|
79
|
+
# Arrow function with expression body
|
|
80
|
+
self.next(self._expecting_func_opening_bracket)
|
|
81
|
+
|
|
82
|
+
def _function_body(self, token):
|
|
83
|
+
if token == '}':
|
|
84
|
+
# End of arrow function body
|
|
85
|
+
self.context.end_of_function()
|
|
86
|
+
self.next(self._expecting_func_opening_bracket)
|
|
87
|
+
|
|
88
|
+
def _expecting_jsx(self, token):
|
|
89
|
+
if token == '>':
|
|
90
|
+
self.next(self._expecting_func_opening_bracket)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class JSXJavaScriptStyleLanguageStates(JavaScriptStyleLanguageStates):
|
|
94
|
+
def __init__(self, context):
|
|
95
|
+
super(JSXJavaScriptStyleLanguageStates, self).__init__(context)
|
|
96
|
+
|
|
97
|
+
def _state_global(self, token):
|
|
98
|
+
if token == 'const' or token == 'let' or token == 'var':
|
|
99
|
+
# Remember that we're in a variable declaration
|
|
100
|
+
self.in_variable_declaration = True
|
|
101
|
+
super()._state_global(token)
|
|
102
|
+
return
|
|
103
|
+
|
|
104
|
+
if hasattr(self, 'in_variable_declaration') and self.in_variable_declaration:
|
|
105
|
+
if token == '=':
|
|
106
|
+
# We're in a variable assignment
|
|
107
|
+
self.function_name = self.last_tokens
|
|
108
|
+
super()._state_global(token)
|
|
109
|
+
return
|
|
110
|
+
elif token == '=>':
|
|
111
|
+
# We're in an arrow function with a variable assignment
|
|
112
|
+
self._push_function_to_stack()
|
|
113
|
+
self._state = self._arrow_function
|
|
114
|
+
return
|
|
115
|
+
elif token == ';' or self.context.newline:
|
|
116
|
+
# End of variable declaration
|
|
117
|
+
self.in_variable_declaration = False
|
|
118
|
+
|
|
119
|
+
super()._state_global(token)
|
|
120
|
+
|
|
121
|
+
def _expecting_func_opening_bracket(self, token):
|
|
122
|
+
if token == ':':
|
|
123
|
+
# Handle type annotations like TypeScript does
|
|
124
|
+
self._consume_type_annotation()
|
|
125
|
+
return
|
|
126
|
+
super()._expecting_func_opening_bracket(token)
|
|
127
|
+
|
|
128
|
+
def _consume_type_annotation(self):
|
|
129
|
+
# Skip over type annotations (simplified version of TypeScript's behavior)
|
|
130
|
+
def skip_until_terminator(token):
|
|
131
|
+
if token in ['{', '=', ';', ')', '(', '=>']:
|
|
132
|
+
self.next(self._state_global, token)
|
|
133
|
+
return True
|
|
134
|
+
return False
|
|
135
|
+
|
|
136
|
+
self.next(skip_until_terminator)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class JSXReader(JavaScriptReader, JSXMixin):
|
|
140
|
+
# pylint: disable=R0903
|
|
141
|
+
|
|
142
|
+
ext = ['jsx']
|
|
143
|
+
language_names = ['jsx']
|
|
144
|
+
|
|
145
|
+
@staticmethod
|
|
146
|
+
@js_style_regex_expression
|
|
147
|
+
def generate_tokens(source_code, addition='', token_class=None):
|
|
148
|
+
# Add support for JSX syntax patterns
|
|
149
|
+
addition = addition + \
|
|
150
|
+
r"|(?:<[A-Za-z][A-Za-z0-9]*(?:\.[A-Za-z][A-Za-z0-9]*)*>)" + \
|
|
151
|
+
r"|(?:<\/[A-Za-z][A-Za-z0-9]*(?:\.[A-Za-z][A-Za-z0-9]*)*>)"
|
|
152
|
+
return JSXMixin.generate_tokens(source_code, addition, token_class)
|
|
153
|
+
|
|
154
|
+
def __init__(self, context):
|
|
155
|
+
super(JSXReader, self).__init__(context)
|
|
156
|
+
# Use our custom JavaScriptStyleLanguageStates subclass
|
|
157
|
+
self.parallel_states = [JSXJavaScriptStyleLanguageStates(context)]
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class XMLTagWithAttrTokenizer(Tokenizer):
|
|
161
|
+
def __init__(self):
|
|
162
|
+
super(XMLTagWithAttrTokenizer, self).__init__()
|
|
163
|
+
self.tag = None
|
|
164
|
+
self.state = self._global_state
|
|
165
|
+
self.cache = ['<']
|
|
166
|
+
self.brace_count = 0 # Track nested braces for complex expressions
|
|
167
|
+
self.arrow_function_detected = False # Track if we've detected an arrow function
|
|
168
|
+
|
|
169
|
+
def process_token(self, token):
|
|
170
|
+
self.cache.append(token)
|
|
171
|
+
if not token.isspace():
|
|
172
|
+
result = self.state(token)
|
|
173
|
+
if result is not None:
|
|
174
|
+
return result
|
|
175
|
+
return ()
|
|
176
|
+
|
|
177
|
+
def abort(self):
|
|
178
|
+
self.stop()
|
|
179
|
+
return self.cache
|
|
180
|
+
|
|
181
|
+
def flush(self):
|
|
182
|
+
tmp, self.cache = self.cache, []
|
|
183
|
+
return [''.join(tmp)]
|
|
184
|
+
|
|
185
|
+
def _global_state(self, token):
|
|
186
|
+
if not isidentifier(token):
|
|
187
|
+
return self.abort()
|
|
188
|
+
self.tag = token
|
|
189
|
+
self.state = self._after_tag
|
|
190
|
+
|
|
191
|
+
def _after_tag(self, token):
|
|
192
|
+
if token == '>':
|
|
193
|
+
self.state = self._body
|
|
194
|
+
elif token == "/":
|
|
195
|
+
self.state = self._expecting_self_closing
|
|
196
|
+
elif isidentifier(token):
|
|
197
|
+
self.state = self._expecting_equal_sign
|
|
198
|
+
else:
|
|
199
|
+
return self.abort()
|
|
200
|
+
|
|
201
|
+
def _expecting_self_closing(self, token):
|
|
202
|
+
if token == ">":
|
|
203
|
+
self.stop()
|
|
204
|
+
return self.flush()
|
|
205
|
+
return self.abort()
|
|
206
|
+
|
|
207
|
+
def _expecting_equal_sign(self, token):
|
|
208
|
+
if token == '=':
|
|
209
|
+
self.state = self._expecting_value
|
|
210
|
+
else:
|
|
211
|
+
return self.abort()
|
|
212
|
+
|
|
213
|
+
def _expecting_value(self, token):
|
|
214
|
+
if token[0] in "'\"":
|
|
215
|
+
self.state = self._after_tag
|
|
216
|
+
elif token == "{":
|
|
217
|
+
self.brace_count = 1 # Start counting braces
|
|
218
|
+
self.state = self._jsx_expression
|
|
219
|
+
# Don't add the closing brace automatically
|
|
220
|
+
# self.cache.append("}")
|
|
221
|
+
self.sub_tokenizer = TSXTokenizer()
|
|
222
|
+
|
|
223
|
+
def _jsx_expression(self, token):
|
|
224
|
+
# Handle nested braces in expressions
|
|
225
|
+
if token == "{":
|
|
226
|
+
self.brace_count += 1
|
|
227
|
+
elif token == "}":
|
|
228
|
+
self.brace_count -= 1
|
|
229
|
+
if self.brace_count == 0:
|
|
230
|
+
# We've found the matching closing brace
|
|
231
|
+
self.state = self._after_tag
|
|
232
|
+
return
|
|
233
|
+
|
|
234
|
+
# Handle arrow functions in JSX attributes
|
|
235
|
+
if token == "=>":
|
|
236
|
+
self.arrow_function_detected = True
|
|
237
|
+
# Explicitly yield the arrow token to ensure it's processed
|
|
238
|
+
return ["=>"]
|
|
239
|
+
|
|
240
|
+
# Handle type annotations in JSX attributes
|
|
241
|
+
if token == "<":
|
|
242
|
+
# This might be a TypeScript generic type annotation
|
|
243
|
+
# We'll continue in the current state and let the tokenizer handle it
|
|
244
|
+
pass
|
|
245
|
+
|
|
246
|
+
def _body(self, token):
|
|
247
|
+
if token == "<":
|
|
248
|
+
self.sub_tokenizer = XMLTagWithAttrTokenizer()
|
|
249
|
+
self.cache.pop()
|
|
250
|
+
return self.flush()
|
|
251
|
+
|
|
252
|
+
if token.startswith("</"):
|
|
253
|
+
self.stop()
|
|
254
|
+
return self.flush()
|
|
255
|
+
|
|
256
|
+
if token == '{':
|
|
257
|
+
self.sub_tokenizer = TSXTokenizer()
|
|
258
|
+
return self.flush()
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def isidentifier(token):
|
|
262
|
+
try:
|
|
263
|
+
return token.isidentifier()
|
|
264
|
+
except AttributeError:
|
|
265
|
+
return token.encode(encoding='UTF-8')[0].isalpha()
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Language parser for Perl
|
|
3
|
+
'''
|
|
4
|
+
|
|
5
|
+
from .code_reader import CodeReader, CodeStateMachine
|
|
6
|
+
from .script_language import ScriptLanguageMixIn
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PerlCommentsMixin(object):
|
|
10
|
+
@staticmethod
|
|
11
|
+
def get_comment_from_token(token):
|
|
12
|
+
if token.startswith('#'):
|
|
13
|
+
return token # Return the entire comment including #
|
|
14
|
+
return None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class PerlReader(CodeReader, ScriptLanguageMixIn):
|
|
18
|
+
# pylint: disable=R0903
|
|
19
|
+
|
|
20
|
+
ext = ['pl', 'pm']
|
|
21
|
+
language_names = ['perl']
|
|
22
|
+
_conditions = set(['if', 'elsif', 'unless', 'while', 'until', 'for', 'foreach', '&&', '||', '?', 'when'])
|
|
23
|
+
|
|
24
|
+
def __init__(self, context):
|
|
25
|
+
super(PerlReader, self).__init__(context)
|
|
26
|
+
self.parallel_states = [PerlStates(context)]
|
|
27
|
+
|
|
28
|
+
def preprocess(self, tokens):
|
|
29
|
+
comment = None
|
|
30
|
+
for token in tokens:
|
|
31
|
+
if comment is not None:
|
|
32
|
+
if token == '\n':
|
|
33
|
+
yield comment
|
|
34
|
+
comment = None
|
|
35
|
+
yield token
|
|
36
|
+
else:
|
|
37
|
+
comment += token
|
|
38
|
+
elif token == '#':
|
|
39
|
+
comment = token
|
|
40
|
+
else:
|
|
41
|
+
yield token
|
|
42
|
+
if comment is not None:
|
|
43
|
+
yield comment
|
|
44
|
+
|
|
45
|
+
def _state(self, token):
|
|
46
|
+
current_state = self.parallel_states[-1]
|
|
47
|
+
if token == '\n':
|
|
48
|
+
return
|
|
49
|
+
return current_state.state(token)
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def get_comment_from_token(token):
|
|
53
|
+
if token.startswith('#'):
|
|
54
|
+
# For forgiveness comments, return the entire comment
|
|
55
|
+
stripped = token.lstrip('#').strip()
|
|
56
|
+
if stripped.startswith('lizard forgives') or stripped.startswith('#lizard forgives'):
|
|
57
|
+
return '#lizard forgives' # Return standardized forgiveness comment
|
|
58
|
+
return stripped # Return the stripped comment for other cases
|
|
59
|
+
return None
|
|
60
|
+
|
|
61
|
+
@staticmethod
|
|
62
|
+
def generate_tokens(source_code, addition='', token_class=None):
|
|
63
|
+
return ScriptLanguageMixIn.generate_common_tokens(source_code, addition, token_class)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class PerlStates(CodeStateMachine):
|
|
67
|
+
_conditions = set(['if', 'elsif', 'unless', 'while', 'until', 'for', 'foreach'])
|
|
68
|
+
|
|
69
|
+
def __init__(self, context):
|
|
70
|
+
super(PerlStates, self).__init__(context)
|
|
71
|
+
self.function_name = ''
|
|
72
|
+
self.brace_count = 0
|
|
73
|
+
self._state = self._state_global
|
|
74
|
+
|
|
75
|
+
def _state_global(self, token):
|
|
76
|
+
if token == 'sub':
|
|
77
|
+
self.function_name = ''
|
|
78
|
+
self.next(self._state_function_dec)
|
|
79
|
+
elif token == '{':
|
|
80
|
+
self.brace_count += 1
|
|
81
|
+
elif token == '}':
|
|
82
|
+
self.brace_count -= 1
|
|
83
|
+
|
|
84
|
+
def _state_function_dec(self, token):
|
|
85
|
+
if token == '{':
|
|
86
|
+
self.brace_count = 1
|
|
87
|
+
if self.function_name:
|
|
88
|
+
self.context.try_new_function(self.function_name)
|
|
89
|
+
self.context.confirm_new_function()
|
|
90
|
+
self.next(self._state_function_body)
|
|
91
|
+
elif token == ';':
|
|
92
|
+
self.next(self._state_global)
|
|
93
|
+
elif not token.isspace():
|
|
94
|
+
self.function_name = token
|
|
95
|
+
|
|
96
|
+
def _state_function_body(self, token):
|
|
97
|
+
if token == '{':
|
|
98
|
+
self.brace_count += 1
|
|
99
|
+
elif token == '}':
|
|
100
|
+
self.brace_count -= 1
|
|
101
|
+
if self.brace_count == 0:
|
|
102
|
+
self.context.end_of_function()
|
|
103
|
+
self.next(self._state_global)
|
|
@@ -16,8 +16,19 @@ class TSXReader(TypeScriptReader, JSXMixin):
|
|
|
16
16
|
@staticmethod
|
|
17
17
|
@js_style_regex_expression
|
|
18
18
|
def generate_tokens(source_code, addition='', token_class=None):
|
|
19
|
+
# Add support for TypeScript type annotations in JSX
|
|
20
|
+
addition = addition + \
|
|
21
|
+
r"|(?:<[A-Za-z][A-Za-z0-9]*(?:\.[A-Za-z][A-Za-z0-9]*)*>)" + \
|
|
22
|
+
r"|(?:<\/[A-Za-z][A-Za-z0-9]*(?:\.[A-Za-z][A-Za-z0-9]*)*>)"
|
|
19
23
|
return JSXMixin.generate_tokens(source_code, addition, token_class)
|
|
20
24
|
|
|
21
25
|
def __init__(self, context):
|
|
22
26
|
super(TSXReader, self).__init__(context)
|
|
23
27
|
# No need for parallel states since JSX handling is in the mixin
|
|
28
|
+
|
|
29
|
+
def _expecting_func_opening_bracket(self, token):
|
|
30
|
+
# Handle TypeScript arrow functions with type annotations in JSX attributes
|
|
31
|
+
if token == ':':
|
|
32
|
+
self._consume_type_annotation()
|
|
33
|
+
return
|
|
34
|
+
super()._expecting_func_opening_bracket(token)
|
|
@@ -111,13 +111,13 @@ class TypeScriptTypeAnnotationStates(CodeStateMachine):
|
|
|
111
111
|
self.next(self._state_simple_type, token)
|
|
112
112
|
|
|
113
113
|
def _state_simple_type(self, token):
|
|
114
|
-
print(token)
|
|
115
114
|
if token == '<':
|
|
116
|
-
print(token)
|
|
117
115
|
self.next(self._state_generic_type, token)
|
|
118
116
|
elif token in '{=;':
|
|
119
117
|
self.saved_token = token
|
|
120
118
|
self.statemachine_return()
|
|
119
|
+
elif token == '(':
|
|
120
|
+
self.next(self._function_type_annotation, token)
|
|
121
121
|
|
|
122
122
|
@CodeStateMachine.read_inside_brackets_then("{}")
|
|
123
123
|
def _inline_type_annotation(self, _):
|
|
@@ -126,3 +126,7 @@ class TypeScriptTypeAnnotationStates(CodeStateMachine):
|
|
|
126
126
|
@CodeStateMachine.read_inside_brackets_then("<>")
|
|
127
127
|
def _state_generic_type(self, token):
|
|
128
128
|
self.statemachine_return()
|
|
129
|
+
|
|
130
|
+
@CodeStateMachine.read_inside_brackets_then("()")
|
|
131
|
+
def _function_type_annotation(self, _):
|
|
132
|
+
self.statemachine_return()
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
'''
|
|
2
|
-
Language parser for JSX
|
|
3
|
-
'''
|
|
4
|
-
|
|
5
|
-
from .javascript import JavaScriptReader
|
|
6
|
-
from .typescript import JSTokenizer, Tokenizer
|
|
7
|
-
from .code_reader import CodeReader
|
|
8
|
-
from .js_style_regex_expression import js_style_regex_expression
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class TSXTokenizer(JSTokenizer):
|
|
12
|
-
def __init__(self):
|
|
13
|
-
super().__init__()
|
|
14
|
-
|
|
15
|
-
def process_token(self, token):
|
|
16
|
-
if token == "<":
|
|
17
|
-
from .jsx import XMLTagWithAttrTokenizer # Import only when needed
|
|
18
|
-
self.sub_tokenizer = XMLTagWithAttrTokenizer()
|
|
19
|
-
return
|
|
20
|
-
|
|
21
|
-
for tok in super().process_token(token):
|
|
22
|
-
yield tok
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class JSXMixin:
|
|
26
|
-
'''Base mixin class for JSX/TSX shared functionality'''
|
|
27
|
-
@staticmethod
|
|
28
|
-
@js_style_regex_expression
|
|
29
|
-
def generate_tokens(source_code, addition='', token_class=None):
|
|
30
|
-
addition = addition +\
|
|
31
|
-
r"|(?:\$\w+)" + \
|
|
32
|
-
r"|(?:\<\/\w+\>)" + \
|
|
33
|
-
r"|`.*?`"
|
|
34
|
-
js_tokenizer = TSXTokenizer()
|
|
35
|
-
for token in CodeReader.generate_tokens(
|
|
36
|
-
source_code, addition, token_class):
|
|
37
|
-
for tok in js_tokenizer(token):
|
|
38
|
-
yield tok
|
|
39
|
-
|
|
40
|
-
def _expecting_func_opening_bracket(self, token):
|
|
41
|
-
if token == '<':
|
|
42
|
-
self.next(self._expecting_jsx)
|
|
43
|
-
return
|
|
44
|
-
super()._expecting_func_opening_bracket(token)
|
|
45
|
-
|
|
46
|
-
def _expecting_jsx(self, token):
|
|
47
|
-
if token == '>':
|
|
48
|
-
self.next(self._expecting_func_opening_bracket)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class JSXReader(JavaScriptReader, JSXMixin):
|
|
52
|
-
# pylint: disable=R0903
|
|
53
|
-
|
|
54
|
-
ext = ['jsx']
|
|
55
|
-
language_names = ['jsx']
|
|
56
|
-
|
|
57
|
-
@staticmethod
|
|
58
|
-
@js_style_regex_expression
|
|
59
|
-
def generate_tokens(source_code, addition='', token_class=None):
|
|
60
|
-
return JSXMixin.generate_tokens(source_code, addition, token_class)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
class XMLTagWithAttrTokenizer(Tokenizer):
|
|
64
|
-
def __init__(self):
|
|
65
|
-
super(XMLTagWithAttrTokenizer, self).__init__()
|
|
66
|
-
self.tag = None
|
|
67
|
-
self.state = self._global_state
|
|
68
|
-
self.cache = ['<']
|
|
69
|
-
|
|
70
|
-
def process_token(self, token):
|
|
71
|
-
self.cache.append(token)
|
|
72
|
-
if not token.isspace():
|
|
73
|
-
result = self.state(token)
|
|
74
|
-
if result is not None:
|
|
75
|
-
return result
|
|
76
|
-
return ()
|
|
77
|
-
|
|
78
|
-
def abort(self):
|
|
79
|
-
self.stop()
|
|
80
|
-
return self.cache
|
|
81
|
-
|
|
82
|
-
def flush(self):
|
|
83
|
-
tmp, self.cache = self.cache, []
|
|
84
|
-
return [''.join(tmp)]
|
|
85
|
-
|
|
86
|
-
def _global_state(self, token):
|
|
87
|
-
if not isidentifier(token):
|
|
88
|
-
return self.abort()
|
|
89
|
-
self.tag = token
|
|
90
|
-
self.state = self._after_tag
|
|
91
|
-
|
|
92
|
-
def _after_tag(self, token):
|
|
93
|
-
if token == '>':
|
|
94
|
-
self.state = self._body
|
|
95
|
-
elif token == "/":
|
|
96
|
-
self.state = self._expecting_self_closing
|
|
97
|
-
elif isidentifier(token):
|
|
98
|
-
self.state = self._expecting_equal_sign
|
|
99
|
-
else:
|
|
100
|
-
return self.abort()
|
|
101
|
-
|
|
102
|
-
def _expecting_self_closing(self, token):
|
|
103
|
-
if token == ">":
|
|
104
|
-
self.stop()
|
|
105
|
-
return self.flush()
|
|
106
|
-
return self.abort()
|
|
107
|
-
|
|
108
|
-
def _expecting_equal_sign(self, token):
|
|
109
|
-
if token == '=':
|
|
110
|
-
self.state = self._expecting_value
|
|
111
|
-
else:
|
|
112
|
-
return self.abort()
|
|
113
|
-
|
|
114
|
-
def _expecting_value(self, token):
|
|
115
|
-
if token[0] in "'\"":
|
|
116
|
-
self.state = self._after_tag
|
|
117
|
-
elif token == "{":
|
|
118
|
-
self.cache.append("}")
|
|
119
|
-
self.sub_tokenizer = TSXTokenizer()
|
|
120
|
-
self.state = self._after_tag
|
|
121
|
-
|
|
122
|
-
def _body(self, token):
|
|
123
|
-
if token == "<":
|
|
124
|
-
self.sub_tokenizer = XMLTagWithAttrTokenizer()
|
|
125
|
-
self.cache.pop()
|
|
126
|
-
return self.flush()
|
|
127
|
-
|
|
128
|
-
if token.startswith("</"):
|
|
129
|
-
self.stop()
|
|
130
|
-
return self.flush()
|
|
131
|
-
|
|
132
|
-
if token == '{':
|
|
133
|
-
self.sub_tokenizer = TSXTokenizer()
|
|
134
|
-
return self.flush()
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
def isidentifier(token):
|
|
138
|
-
try:
|
|
139
|
-
return token.isidentifier()
|
|
140
|
-
except AttributeError:
|
|
141
|
-
return token.encode(encoding='UTF-8')[0].isalpha()
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|