ljavalang 2.0.1__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.
- javalang/__init__.py +8 -0
- javalang/ast.py +86 -0
- javalang/javadoc.py +120 -0
- javalang/parse.py +53 -0
- javalang/parser.py +2884 -0
- javalang/test/__init__.py +0 -0
- javalang/test/source/package-info/AnnotationJavadoc.java +5 -0
- javalang/test/source/package-info/AnnotationOnly.java +2 -0
- javalang/test/source/package-info/JavadocAnnotation.java +5 -0
- javalang/test/source/package-info/JavadocOnly.java +4 -0
- javalang/test/source/package-info/NoAnnotationNoJavadoc.java +1 -0
- javalang/test/test_java_10_11_syntax.py +66 -0
- javalang/test/test_java_14_15_syntax.py +195 -0
- javalang/test/test_java_16_17_syntax.py +99 -0
- javalang/test/test_java_21_syntax.py +140 -0
- javalang/test/test_java_8_syntax.py +241 -0
- javalang/test/test_java_9_syntax.py +115 -0
- javalang/test/test_javadoc.py +14 -0
- javalang/test/test_package_declaration.py +61 -0
- javalang/test/test_tokenizer.py +192 -0
- javalang/test/test_upstream_features.py +120 -0
- javalang/test/test_upstream_issues.py +176 -0
- javalang/test/test_util.py +69 -0
- javalang/tokenizer.py +687 -0
- javalang/tree.py +340 -0
- javalang/util.py +165 -0
- javalang/visitor.py +48 -0
- ljavalang-2.0.1.dist-info/LICENSE.txt +19 -0
- ljavalang-2.0.1.dist-info/METADATA +279 -0
- ljavalang-2.0.1.dist-info/RECORD +32 -0
- ljavalang-2.0.1.dist-info/WHEEL +5 -0
- ljavalang-2.0.1.dist-info/top_level.txt +1 -0
javalang/__init__.py
ADDED
javalang/ast.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import pickle
|
|
2
|
+
|
|
3
|
+
import six
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class MetaNode(type):
|
|
7
|
+
def __new__(mcs, name, bases, dict):
|
|
8
|
+
attrs = list(dict['attrs'])
|
|
9
|
+
dict['attrs'] = list()
|
|
10
|
+
|
|
11
|
+
for base in bases:
|
|
12
|
+
if hasattr(base, 'attrs'):
|
|
13
|
+
dict['attrs'].extend(base.attrs)
|
|
14
|
+
|
|
15
|
+
dict['attrs'].extend(attrs)
|
|
16
|
+
|
|
17
|
+
return type.__new__(mcs, name, bases, dict)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@six.add_metaclass(MetaNode)
|
|
21
|
+
class Node(object):
|
|
22
|
+
attrs = ()
|
|
23
|
+
|
|
24
|
+
def __init__(self, **kwargs):
|
|
25
|
+
values = kwargs.copy()
|
|
26
|
+
|
|
27
|
+
for attr_name in self.attrs:
|
|
28
|
+
value = values.pop(attr_name, None)
|
|
29
|
+
setattr(self, attr_name, value)
|
|
30
|
+
|
|
31
|
+
if values:
|
|
32
|
+
raise ValueError('Extraneous arguments')
|
|
33
|
+
|
|
34
|
+
def __equals__(self, other):
|
|
35
|
+
if type(other) is not type(self):
|
|
36
|
+
return False
|
|
37
|
+
|
|
38
|
+
for attr in self.attrs:
|
|
39
|
+
if getattr(other, attr) != getattr(self, attr):
|
|
40
|
+
return False
|
|
41
|
+
|
|
42
|
+
return True
|
|
43
|
+
|
|
44
|
+
def __repr__(self):
|
|
45
|
+
attr_values = []
|
|
46
|
+
for attr in sorted(self.attrs):
|
|
47
|
+
attr_values.append('%s=%s' % (attr, getattr(self, attr)))
|
|
48
|
+
return '%s(%s)' % (type(self).__name__, ', '.join(attr_values))
|
|
49
|
+
|
|
50
|
+
def __iter__(self):
|
|
51
|
+
return walk_tree(self)
|
|
52
|
+
|
|
53
|
+
def filter(self, pattern):
|
|
54
|
+
for path, node in self:
|
|
55
|
+
if ((isinstance(pattern, type) and isinstance(node, pattern)) or
|
|
56
|
+
(node == pattern)):
|
|
57
|
+
yield path, node
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def children(self):
|
|
61
|
+
return [getattr(self, attr_name) for attr_name in self.attrs]
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def position(self):
|
|
65
|
+
if hasattr(self, "_position"):
|
|
66
|
+
return self._position
|
|
67
|
+
|
|
68
|
+
def walk_tree(root):
|
|
69
|
+
children = None
|
|
70
|
+
|
|
71
|
+
if isinstance(root, Node):
|
|
72
|
+
yield (), root
|
|
73
|
+
children = root.children
|
|
74
|
+
else:
|
|
75
|
+
children = root
|
|
76
|
+
|
|
77
|
+
for child in children:
|
|
78
|
+
if isinstance(child, (Node, list, tuple)):
|
|
79
|
+
for path, node in walk_tree(child):
|
|
80
|
+
yield (root,) + path, node
|
|
81
|
+
|
|
82
|
+
def dump(ast, file):
|
|
83
|
+
pickle.dump(ast, file)
|
|
84
|
+
|
|
85
|
+
def load(file):
|
|
86
|
+
return pickle.load(file)
|
javalang/javadoc.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
|
|
2
|
+
import re
|
|
3
|
+
|
|
4
|
+
def join(s):
|
|
5
|
+
return ' '.join(l.strip() for l in s.split('\n'))
|
|
6
|
+
|
|
7
|
+
class DocBlock(object):
|
|
8
|
+
def __init__(self):
|
|
9
|
+
self.description = ''
|
|
10
|
+
self.return_doc = None
|
|
11
|
+
self.params = []
|
|
12
|
+
|
|
13
|
+
self.authors = []
|
|
14
|
+
self.deprecated = False
|
|
15
|
+
|
|
16
|
+
# @exception and @throw are equivalent
|
|
17
|
+
self.throws = {}
|
|
18
|
+
self.exceptions = self.throws
|
|
19
|
+
|
|
20
|
+
self.tags = {}
|
|
21
|
+
|
|
22
|
+
def add_block(self, name, value):
|
|
23
|
+
value = value.strip()
|
|
24
|
+
|
|
25
|
+
if name == 'param':
|
|
26
|
+
try:
|
|
27
|
+
param, description = value.split(None, 1)
|
|
28
|
+
except ValueError:
|
|
29
|
+
param, description = value, ''
|
|
30
|
+
self.params.append((param, join(description)))
|
|
31
|
+
|
|
32
|
+
elif name in ('throws', 'exception'):
|
|
33
|
+
try:
|
|
34
|
+
ex, description = value.split(None, 1)
|
|
35
|
+
except ValueError:
|
|
36
|
+
ex, description = value, ''
|
|
37
|
+
self.throws[ex] = join(description)
|
|
38
|
+
|
|
39
|
+
elif name == 'return':
|
|
40
|
+
self.return_doc = value
|
|
41
|
+
|
|
42
|
+
elif name == 'author':
|
|
43
|
+
self.authors.append(value)
|
|
44
|
+
|
|
45
|
+
elif name == 'deprecated':
|
|
46
|
+
self.deprecated = True
|
|
47
|
+
|
|
48
|
+
self.tags.setdefault(name, []).append(value)
|
|
49
|
+
|
|
50
|
+
blocks_re = re.compile('(^@)', re.MULTILINE)
|
|
51
|
+
leading_space_re = re.compile(r'^\s*\*', re.MULTILINE)
|
|
52
|
+
blocks_justify_re = re.compile(r'^\s*@', re.MULTILINE)
|
|
53
|
+
|
|
54
|
+
def _sanitize(s):
|
|
55
|
+
s = s.strip()
|
|
56
|
+
|
|
57
|
+
if not (s[:3] == '/**' and s[-2:] == '*/'):
|
|
58
|
+
raise ValueError('not a valid Javadoc comment')
|
|
59
|
+
|
|
60
|
+
s = s.replace('\t', ' ')
|
|
61
|
+
|
|
62
|
+
return s
|
|
63
|
+
|
|
64
|
+
def _uncomment(s):
|
|
65
|
+
# Remove /** and */
|
|
66
|
+
s = s[3:-2].strip()
|
|
67
|
+
|
|
68
|
+
return leading_space_re.sub('', s)
|
|
69
|
+
|
|
70
|
+
def _get_indent_level(s):
|
|
71
|
+
return len(s) - len(s.lstrip())
|
|
72
|
+
|
|
73
|
+
def _left_justify(s):
|
|
74
|
+
lines = s.rstrip().splitlines()
|
|
75
|
+
|
|
76
|
+
if not lines:
|
|
77
|
+
return ''
|
|
78
|
+
|
|
79
|
+
indent_levels = []
|
|
80
|
+
for line in lines:
|
|
81
|
+
if line.strip():
|
|
82
|
+
indent_levels.append(_get_indent_level(line))
|
|
83
|
+
indent_levels.sort()
|
|
84
|
+
|
|
85
|
+
common_indent = indent_levels[0]
|
|
86
|
+
if common_indent == 0:
|
|
87
|
+
return s
|
|
88
|
+
else:
|
|
89
|
+
lines = [line[common_indent:] for line in lines]
|
|
90
|
+
return '\n'.join(lines)
|
|
91
|
+
|
|
92
|
+
def _force_blocks_left(s):
|
|
93
|
+
return blocks_justify_re.sub('@', s)
|
|
94
|
+
|
|
95
|
+
def parse(raw):
|
|
96
|
+
sanitized = _sanitize(raw)
|
|
97
|
+
uncommented = _uncomment(sanitized)
|
|
98
|
+
justified = _left_justify(uncommented)
|
|
99
|
+
justified_fixed = _force_blocks_left(justified)
|
|
100
|
+
prepared = justified_fixed
|
|
101
|
+
|
|
102
|
+
blocks = blocks_re.split(prepared)
|
|
103
|
+
|
|
104
|
+
doc = DocBlock()
|
|
105
|
+
|
|
106
|
+
if blocks[0] != '@':
|
|
107
|
+
doc.description = blocks[0].strip()
|
|
108
|
+
blocks = blocks[2::2]
|
|
109
|
+
else:
|
|
110
|
+
blocks = blocks[1::2]
|
|
111
|
+
|
|
112
|
+
for block in blocks:
|
|
113
|
+
try:
|
|
114
|
+
tag, value = block.split(None, 1)
|
|
115
|
+
except ValueError:
|
|
116
|
+
tag, value = block, ''
|
|
117
|
+
|
|
118
|
+
doc.add_block(tag, value)
|
|
119
|
+
|
|
120
|
+
return doc
|
javalang/parse.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
|
|
2
|
+
from .parser import Parser
|
|
3
|
+
from .tokenizer import tokenize
|
|
4
|
+
|
|
5
|
+
def parse_expression(exp):
|
|
6
|
+
if not exp.endswith(';'):
|
|
7
|
+
exp = exp + ';'
|
|
8
|
+
|
|
9
|
+
tokens = tokenize(exp)
|
|
10
|
+
parser = Parser(tokens)
|
|
11
|
+
|
|
12
|
+
return parser.parse_expression()
|
|
13
|
+
|
|
14
|
+
def parse_member_signature(sig):
|
|
15
|
+
if not sig.endswith(';'):
|
|
16
|
+
sig = sig + ';'
|
|
17
|
+
|
|
18
|
+
tokens = tokenize(sig)
|
|
19
|
+
parser = Parser(tokens)
|
|
20
|
+
|
|
21
|
+
return parser.parse_member_declaration()
|
|
22
|
+
|
|
23
|
+
def parse_constructor_signature(sig):
|
|
24
|
+
# Add an empty body to the signature, replacing a ; if necessary
|
|
25
|
+
if sig.endswith(';'):
|
|
26
|
+
sig = sig[:-1]
|
|
27
|
+
sig = sig + '{ }'
|
|
28
|
+
|
|
29
|
+
tokens = tokenize(sig)
|
|
30
|
+
parser = Parser(tokens)
|
|
31
|
+
|
|
32
|
+
return parser.parse_member_declaration()
|
|
33
|
+
|
|
34
|
+
def parse_type(s):
|
|
35
|
+
tokens = tokenize(s)
|
|
36
|
+
parser = Parser(tokens)
|
|
37
|
+
|
|
38
|
+
return parser.parse_type()
|
|
39
|
+
|
|
40
|
+
def parse_type_signature(sig):
|
|
41
|
+
if sig.endswith(';'):
|
|
42
|
+
sig = sig[:-1]
|
|
43
|
+
sig = sig + '{ }'
|
|
44
|
+
|
|
45
|
+
tokens = tokenize(sig)
|
|
46
|
+
parser = Parser(tokens)
|
|
47
|
+
|
|
48
|
+
return parser.parse_class_or_interface_declaration()
|
|
49
|
+
|
|
50
|
+
def parse(s):
|
|
51
|
+
tokens = tokenize(s)
|
|
52
|
+
parser = Parser(tokens)
|
|
53
|
+
return parser.parse()
|