1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.github.tonywasher.joceanus.themis.xanalysis.parser;
18
19 import com.github.javaparser.JavaParser;
20 import com.github.javaparser.ParseResult;
21 import com.github.javaparser.ParserConfiguration;
22 import com.github.javaparser.Position;
23 import com.github.javaparser.Problem;
24 import com.github.javaparser.ast.CompilationUnit;
25 import com.github.javaparser.ast.Node;
26 import com.github.javaparser.ast.NodeList;
27 import com.github.javaparser.ast.PackageDeclaration;
28 import com.github.javaparser.ast.body.BodyDeclaration;
29 import com.github.javaparser.ast.expr.Expression;
30 import com.github.javaparser.ast.modules.ModuleDeclaration;
31 import com.github.javaparser.ast.stmt.Statement;
32 import com.github.javaparser.ast.type.Type;
33 import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
34 import io.github.tonywasher.joceanus.themis.exc.ThemisDataException;
35 import io.github.tonywasher.joceanus.themis.exc.ThemisIOException;
36 import io.github.tonywasher.joceanus.themis.xanalysis.parser.base.ThemisXAnalysisChar;
37 import io.github.tonywasher.joceanus.themis.xanalysis.parser.base.ThemisXAnalysisInstance;
38 import io.github.tonywasher.joceanus.themis.xanalysis.parser.base.ThemisXAnalysisInstance.ThemisXAnalysisClassInstance;
39 import io.github.tonywasher.joceanus.themis.xanalysis.parser.base.ThemisXAnalysisInstance.ThemisXAnalysisDeclarationInstance;
40 import io.github.tonywasher.joceanus.themis.xanalysis.parser.base.ThemisXAnalysisInstance.ThemisXAnalysisExpressionInstance;
41 import io.github.tonywasher.joceanus.themis.xanalysis.parser.base.ThemisXAnalysisInstance.ThemisXAnalysisModuleInstance;
42 import io.github.tonywasher.joceanus.themis.xanalysis.parser.base.ThemisXAnalysisInstance.ThemisXAnalysisNodeInstance;
43 import io.github.tonywasher.joceanus.themis.xanalysis.parser.base.ThemisXAnalysisInstance.ThemisXAnalysisStatementInstance;
44 import io.github.tonywasher.joceanus.themis.xanalysis.parser.base.ThemisXAnalysisInstance.ThemisXAnalysisTypeInstance;
45 import io.github.tonywasher.joceanus.themis.xanalysis.parser.base.ThemisXAnalysisModifierList;
46 import io.github.tonywasher.joceanus.themis.xanalysis.parser.base.ThemisXAnalysisParserDef;
47 import io.github.tonywasher.joceanus.themis.xanalysis.parser.decl.ThemisXAnalysisDeclParser;
48 import io.github.tonywasher.joceanus.themis.xanalysis.parser.expr.ThemisXAnalysisExprParser;
49 import io.github.tonywasher.joceanus.themis.xanalysis.parser.mod.ThemisXAnalysisModModule;
50 import io.github.tonywasher.joceanus.themis.xanalysis.parser.mod.ThemisXAnalysisModParser;
51 import io.github.tonywasher.joceanus.themis.xanalysis.parser.node.ThemisXAnalysisNodeCompilationUnit;
52 import io.github.tonywasher.joceanus.themis.xanalysis.parser.node.ThemisXAnalysisNodeParser;
53 import io.github.tonywasher.joceanus.themis.xanalysis.parser.proj.ThemisXAnalysisProject;
54 import io.github.tonywasher.joceanus.themis.xanalysis.parser.stmt.ThemisXAnalysisStmtParser;
55 import io.github.tonywasher.joceanus.themis.xanalysis.parser.type.ThemisXAnalysisTypeParser;
56
57 import java.io.File;
58 import java.io.FileInputStream;
59 import java.io.IOException;
60 import java.io.InputStream;
61 import java.nio.charset.StandardCharsets;
62 import java.util.ArrayDeque;
63 import java.util.ArrayList;
64 import java.util.Deque;
65 import java.util.List;
66
67
68
69
70 public class ThemisXAnalysisParser
71 implements ThemisXAnalysisParserDef {
72
73
74
75 private final JavaParser theParser;
76
77
78
79
80 private final Deque<ThemisXAnalysisInstance> theNodes;
81
82
83
84
85 private String thePackage;
86
87
88
89
90 private File theCurrentFile;
91
92
93
94
95 private final List<ThemisXAnalysisClassInstance> theClasses;
96
97
98
99
100 private final Deque<String> theClassStack;
101
102
103
104
105 private int theClassIndex;
106
107
108
109
110 private ThemisXAnalysisProject theProject;
111
112
113
114
115 private OceanusException theError;
116
117
118
119
120
121
122 public ThemisXAnalysisParser(final File pLocation) {
123
124 theParser = new JavaParser();
125 theNodes = new ArrayDeque<>();
126 theClassStack = new ArrayDeque<>();
127 theClasses = new ArrayList<>();
128
129
130 try {
131
132 theProject = new ThemisXAnalysisProject(pLocation);
133
134
135 configureParser();
136
137
138 theProject.parseJavaCode(this);
139
140
141 } catch (OceanusException e) {
142 theError = e;
143 theProject = null;
144 }
145 }
146
147
148
149
150
151
152 public ThemisXAnalysisProject getProject() {
153 return theProject;
154 }
155
156
157
158
159
160
161 public OceanusException getError() {
162 return theError;
163 }
164
165 @Override
166 public List<ThemisXAnalysisClassInstance> getClasses() {
167 return theClasses;
168 }
169
170
171
172
173 private void configureParser() {
174
175 final ParserConfiguration myConfig = theParser.getParserConfiguration();
176 myConfig.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_21);
177 }
178
179 @Override
180 public void setCurrentPackage(final String pPackage) {
181 thePackage = pPackage;
182 }
183
184 @Override
185 public void setCurrentFile(final File pFile) {
186 theCurrentFile = pFile;
187 theClasses.clear();
188 theClassStack.clear();
189 theClassIndex = 0;
190 }
191
192 @Override
193 public ThemisXAnalysisInstance registerInstance(final ThemisXAnalysisInstance pInstance) {
194
195 final ThemisXAnalysisInstance myParent = theNodes.peekLast();
196 if (myParent != null) {
197 myParent.registerChild(pInstance);
198 }
199
200
201 theNodes.addLast(pInstance);
202 return myParent;
203 }
204
205
206
207
208
209
210 private void deRegisterInstance(final ThemisXAnalysisInstance pInstance) {
211
212 if (pInstance != null) {
213
214 final ThemisXAnalysisInstance myCurrent = theNodes.peekLast();
215 if (pInstance.equals(myCurrent)) {
216
217 theNodes.removeLast();
218 }
219 if (pInstance instanceof ThemisXAnalysisClassInstance) {
220 theClassStack.removeLast();
221 }
222 }
223 }
224
225 @Override
226 public String registerClass(final ThemisXAnalysisClassInstance pClass) {
227
228 theClasses.add(pClass);
229
230
231 String myFullName = pClass.getFullName();
232 if (myFullName == null) {
233 final String myCurrentName = theClassStack.peekLast();
234 myFullName = myCurrentName
235 + ThemisXAnalysisChar.PERIOD
236 + ThemisXAnalysisChar.DOLLAR
237 + ++theClassIndex;
238 if (pClass.isLocalDeclaration()) {
239 myFullName += pClass.getName();
240 }
241 }
242
243
244 theClassStack.addLast(myFullName);
245
246
247 return myFullName;
248 }
249
250 @Override
251 public ThemisXAnalysisNodeCompilationUnit parseJavaFile() throws OceanusException {
252
253 try (InputStream myStream = new FileInputStream(theCurrentFile)) {
254
255 final ParseResult<CompilationUnit> myUnit = theParser.parse(myStream);
256 if (!myUnit.isSuccessful()) {
257 final Problem myProblem = myUnit.getProblem(0);
258 throw new ThemisDataException(myProblem.getVerboseMessage());
259 }
260 return (ThemisXAnalysisNodeCompilationUnit) parseNode(myUnit.getResult().orElse(null));
261
262
263 } catch (IOException e) {
264
265 throw new ThemisIOException("Failed to load file "
266 + theCurrentFile.getAbsolutePath(), e);
267 }
268 }
269
270 @Override
271 public ThemisXAnalysisModModule parseModuleInfo(final File pInfoFile) throws OceanusException {
272
273 setCurrentFile(pInfoFile);
274 try (InputStream myStream = new FileInputStream(theCurrentFile)) {
275
276 final String myText = new String(myStream.readAllBytes(), StandardCharsets.UTF_8);
277 final ParseResult<ModuleDeclaration> myDecl = theParser.parseModuleDeclaration(myText);
278 if (!myDecl.isSuccessful()) {
279 final Problem myProblem = myDecl.getProblem(0);
280 throw new ThemisDataException(myProblem.getVerboseMessage());
281 }
282 return (ThemisXAnalysisModModule) parseModule(myDecl.getResult().orElse(null));
283
284
285 } catch (IOException e) {
286
287 throw new ThemisIOException("Failed to load file "
288 + theCurrentFile.getAbsolutePath(), e);
289 }
290 }
291
292 @Override
293 public OceanusException buildException(final String pMessage,
294 final Node pNode) {
295
296 final Position myPos = pNode.getBegin().orElse(null);
297 final String myLocation = pNode.getClass().getCanonicalName()
298 + (myPos == null ? "" : ThemisXAnalysisChar.PARENTHESIS_OPEN
299 + myPos.line
300 + ThemisXAnalysisChar.COLON
301 + myPos.column
302 + ThemisXAnalysisChar.PARENTHESIS_CLOSE);
303
304
305 final String myMsg = pMessage
306 + ThemisXAnalysisChar.LF
307 + myLocation
308 + ThemisXAnalysisChar.LF
309 + theCurrentFile.getAbsolutePath();
310
311
312 return new ThemisDataException(myMsg);
313 }
314
315
316
317
318
319
320
321 public void checkPackage(final PackageDeclaration pPackage) throws OceanusException {
322
323 if (!thePackage.equals(pPackage.getNameAsString())) {
324 throw buildException("Mismatch on package", pPackage);
325 }
326 }
327
328 @Override
329 public ThemisXAnalysisDeclarationInstance parseDeclaration(final BodyDeclaration<?> pDecl) throws OceanusException {
330 final ThemisXAnalysisDeclarationInstance myInstance = ThemisXAnalysisDeclParser.parseDeclaration(this, pDecl);
331 deRegisterInstance(myInstance);
332 return myInstance;
333 }
334
335 @Override
336 public ThemisXAnalysisNodeInstance parseNode(final Node pNode) throws OceanusException {
337 final ThemisXAnalysisNodeInstance myInstance = ThemisXAnalysisNodeParser.parseNode(this, pNode);
338 deRegisterInstance(myInstance);
339 return myInstance;
340 }
341
342 @Override
343 public ThemisXAnalysisTypeInstance parseType(final Type pType) throws OceanusException {
344 final ThemisXAnalysisTypeInstance myInstance = ThemisXAnalysisTypeParser.parseType(this, pType);
345 deRegisterInstance(myInstance);
346 return myInstance;
347 }
348
349 @Override
350 public ThemisXAnalysisStatementInstance parseStatement(final Statement pStatement) throws OceanusException {
351 final ThemisXAnalysisStatementInstance myInstance = ThemisXAnalysisStmtParser.parseStatement(this, pStatement);
352 deRegisterInstance(myInstance);
353 return myInstance;
354 }
355
356 @Override
357 public ThemisXAnalysisExpressionInstance parseExpression(final Expression pExpr) throws OceanusException {
358 final ThemisXAnalysisExpressionInstance myInstance = ThemisXAnalysisExprParser.parseExpression(this, pExpr);
359 deRegisterInstance(myInstance);
360 return myInstance;
361 }
362
363 @Override
364 public ThemisXAnalysisModuleInstance parseModule(final Node pMod) throws OceanusException {
365 final ThemisXAnalysisModuleInstance myInstance = ThemisXAnalysisModParser.parseModule(this, pMod);
366 deRegisterInstance(myInstance);
367 return myInstance;
368 }
369
370 @Override
371 public ThemisXAnalysisModifierList parseModifierList(final NodeList<? extends Node> pNodeList) throws OceanusException {
372 return ThemisXAnalysisNodeParser.parseModifierList(this, pNodeList);
373 }
374 }