Coverage for C:\leo.repo\leo-editor\leo\plugins\importers\java.py : 88%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#@+leo-ver=5-thin
2#@+node:ekr.20140723122936.18143: * @file ../plugins/importers/java.py
3"""The @auto importer for the java language."""
4import re
5from leo.core import leoGlobals as g
6from leo.plugins.importers import linescanner
7assert g
8Importer = linescanner.Importer
9Target = linescanner.Target
10#@+others
11#@+node:ekr.20161126161824.2: ** class Java_Importer
12class Java_Importer(Importer):
13 """The importer for the java lanuage."""
15 def __init__(self, importCommands, **kwargs):
16 """Java_Importer.__init__"""
17 super().__init__(
18 importCommands,
19 language='java',
20 state_class=Java_ScanState,
21 strict=False,
22 )
24 # Used in multiple methods.
25 java_keywords = (
26 '(break|case|catch|continue|default|do|else|enum|' +
27 'finally|for|goto|if|new|return|' +
28 'sizeof|strictfp|struct|super|switch|this|throw|throws|try|while)'
29 )
30 java_types_list = (
31 '(abstract|boolean|byte|char|const|double|extends|final|float|int|' +
32 'interface|long|native|package|private|protected|public|' +
33 'short|static|transient|void|volatile)'
34 )
35 # 'signed|typedef|union|unsigned)'
36 java_types_pattern = re.compile(java_types_list)
37 java_keywords_pattern = re.compile(java_keywords)
39 #@+others
40 #@+node:ekr.20161126163014.1: *3* java_i.clean_headline
41 def clean_headline(self, s, p=None):
42 """Return the cleaned headline."""
43 return s.strip('{').strip() if s.strip().endswith('{') else s.strip()
44 #@+node:ekr.20161205042019.2: *3* java_i.match_name_patterns
45 java_name_pattern = re.compile(r'\s*([\w:]+)')
47 def match_name_patterns(self, line):
48 """Set self.headline if the line defines a typedef name."""
49 m = self.java_name_pattern.match(line)
50 if m:
51 word = m.group(1)
52 if not self.java_types_pattern.match(word):
53 self.headline = word
54 #@+node:ekr.20161205042019.3: *3* java_i.match_start_patterns
55 # Define patterns that can start a block
56 java_class_pattern = re.compile(r'\s*(%s\s*)*\s*class\s+(\w+)' % (java_types_list))
57 java_func_pattern = re.compile(r'\s*(%s\s*)+\s*([\w:]+)' % (java_types_list))
59 def match_start_patterns(self, line):
60 """
61 True if line matches any block-starting pattern.
62 If true, set self.headline.
63 """
64 m = self.java_class_pattern.match(line)
65 if m:
66 self.headline = line
67 return True
68 m = self.java_func_pattern.match(line)
69 if m:
70 i = line.find('(')
71 self.headline = line[:i] if i > -1 else line
72 return True
73 return False
74 #@+node:ekr.20161205042019.4: *3* java_i.start_new_block
75 def start_new_block(self, i, lines, new_state, prev_state, stack):
76 """Create a child node and update the stack."""
77 line = lines[i]
78 target = stack[-1]
79 # Insert the reference in *this* node.
80 h = self.gen_ref(line, target.p, target)
81 # Create a new child and associated target.
82 if self.headline:
83 h = self.headline
84 if new_state.level() > prev_state.level():
85 child = self.create_child_node(target.p, line, h)
86 else:
87 # We may not have seen the { yet, so adjust.
88 # Without this, the new block becomes a child of the preceding.
89 new_state = Java_ScanState()
90 new_state.curlies = prev_state.curlies + 1
91 child = self.create_child_node(target.p, line, h)
92 stack.append(Target(child, new_state))
93 # Add all additional lines of the signature.
94 skip = self.skip # Don't change the ivar!
95 while skip > 0:
96 skip -= 1
97 i += 1
98 assert i < len(lines), (i, len(lines))
99 line = lines[i]
100 if not self.headline:
101 self.match_name_patterns(line)
102 if self.headline:
103 child.h = '%s %s' % (child.h.strip(), self.headline)
104 self.add_line(child, lines[i])
105 #@+node:ekr.20161205042019.5: *3* java_i.starts_block
106 def starts_block(self, i, lines, new_state, prev_state):
107 """True if the new state starts a block."""
108 self.headline = None
109 line = lines[i]
110 if prev_state.context:
111 return False
112 if self.java_keywords_pattern.match(line):
113 return False
114 if not self.match_start_patterns(line):
115 return False
116 # Must not be a complete statement.
117 if line.find(';') > -1:
118 return False
119 # Scan ahead until an open { is seen. the skip count.
120 self.skip = 0
121 while self.skip < 10:
122 if new_state.level() > prev_state.level():
123 return True
124 self.skip += 1
125 i += 1
126 if i < len(lines):
127 line = lines[i]
128 prev_state = new_state
129 new_state = self.scan_line(line, prev_state)
130 else:
131 break
132 return False
133 #@-others
134#@+node:ekr.20161126161824.6: ** class class Java_ScanState
135class Java_ScanState:
136 """A class representing the state of the java line-oriented scan."""
138 def __init__(self, d=None):
139 """Java_ScanState.__init__"""
140 if d:
141 prev = d.get('prev')
142 self.context = prev.context
143 self.curlies = prev.curlies
144 else:
145 self.context = ''
146 self.curlies = 0
148 def __repr__(self):
149 """Java_ScanState.__repr__"""
150 return "Java_ScanState context: %r curlies: %s" % (
151 self.context, self.curlies)
153 __str__ = __repr__
155 #@+others
156 #@+node:ekr.20161126161824.7: *3* java_state.level
157 def level(self):
158 """Java_ScanState.level."""
159 return self.curlies
161 #@+node:ekr.20161126161824.8: *3* java_state.update
162 def update(self, data):
163 """
164 Java_ScanState.update
166 Update the state using the 6-tuple returned by i.scan_line.
167 Return i = data[1]
168 """
169 context, i, delta_c, delta_p, delta_s, bs_nl = data
170 # All ScanState classes must have a context ivar.
171 self.context = context
172 self.curlies += delta_c
173 return i
174 #@-others
175#@-others
176importer_dict = {
177 'func': Java_Importer.do_import(),
178 'extensions': ['.java'],
179}
180#@@language python
181#@@tabwidth -4
182#@-leo