diff --git a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/FxcaMain.java b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/FxcaMain.java index b3847434c4016842d4405c5a53ba2dbfda18413d..f7acc24af19ce634b22ca61d180c90a043df14f5 100644 --- a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/FxcaMain.java +++ b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/FxcaMain.java @@ -47,9 +47,6 @@ import org.oceandsl.tools.fxca.tools.IOUtils; public final class FxcaMain extends AbstractService<TeetimeConfiguration, Settings> { private static final Logger LOGGER = LoggerFactory.getLogger(FxcaMain.class); - private static final String OPERATION_DEFINITIONS = "operation-definitions.csv"; - private static final String CALL_TABLE = "calltable.csv"; - private static final String NOT_FOUND = "notfound.csv"; /** * As suggested by PMD, make this a utility class that cannot be instantiated. @@ -68,91 +65,6 @@ public final class FxcaMain extends AbstractService<TeetimeConfiguration, Settin } } -// private static void processModules(final FortranProject projectModel, final Path inputPath, -// final Path outputDirectoryPath) { -// final List<FortranModule> namelessModules = new ArrayList<>(); -// -// FxcaMain.LOGGER.info("Added modules from {}.", inputPath); -// -// try (final OutputStream outputStream = Files -// .newOutputStream(outputDirectoryPath.resolve(FxcaMain.OPERATION_DEFINITIONS))) { -// final PrintStream operationListOutput = new PrintStream(outputStream); -// -// operationListOutput.println("file,operation"); -// -// for (final FortranModule fortranModule : projectModel.getModules().values()) { -// if (!fortranModule.isNamedModule()) { -// namelessModules.add(fortranModule); -// } -// -// FxcaMain.LOGGER.debug("operation declarations:"); -// -// try { -// for (final String operationName : fortranModule.computeOperationDeclarations()) { -// operationListOutput -// .println(fortranModule.getXmlFilePath().toAbsolutePath().getFileName().toString() + "," -// + operationName); -// } -// } catch (ParserConfigurationException | SAXException e) { -// FxcaMain.LOGGER.error("Cannot process module {}: {}", fortranModule.getModuleName(), -// e.getLocalizedMessage()); -// } -// -// FxcaMain.LOGGER.debug("subroutine calls of {}: ", fortranModule.getXmlFilePath()); -// try { -// fortranModule.subroutineCalls() -// .forEach(pair -> FxcaMain.LOGGER.info("call: {} --> {}", pair.first, pair.second)); -// } catch (ParserConfigurationException | SAXException e) { -// FxcaMain.LOGGER.error("Cannot process subroutine calls for module {}: {}", -// fortranModule.getModuleName(), e.getLocalizedMessage()); -// } -// -// FxcaMain.LOGGER.debug("function calls of {}:", fortranModule.getXmlFilePath()); -// try { -// fortranModule.functionCalls() -// .forEach(pair -> FxcaMain.LOGGER.info("call: {} --> {}", pair.first, pair.second)); -// } catch (ParserConfigurationException | SAXException e) { -// FxcaMain.LOGGER.error("Cannot process function calls for module {}: {}", -// fortranModule.getModuleName(), e.getLocalizedMessage()); -// } -// -// FxcaMain.LOGGER.debug("node types:"); -// try { -// IOUtils.printWithCommas( -// fortranModule.computeAllNodeAttributes(node -> StatementNode.nodeType(node.getNodeType()))); -// } catch (ParserConfigurationException | SAXException e) { -// FxcaMain.LOGGER.error("Cannot output node attribute for module {}: {}", -// fortranModule.getModuleName(), e.getLocalizedMessage()); -// } -// -// FxcaMain.LOGGER.debug("node names:"); -// try { -// IOUtils.printWithCommas(fortranModule.computeAllNodeAttributes(node -> node.getNodeName())); -// } catch (ParserConfigurationException | SAXException e) { -// FxcaMain.LOGGER.error("Cannot output node names for module {}: {}", fortranModule.getModuleName(), -// e.getLocalizedMessage()); -// } -// } -// -// final PrintStream tableOutput = new PrintStream( -// Files.newOutputStream(outputDirectoryPath.resolve(FxcaMain.CALL_TABLE))); -// final PrintStream errorOutput = new PrintStream( -// Files.newOutputStream(outputDirectoryPath.resolve(FxcaMain.NOT_FOUND))); -// -//// try { -//// projectModel.exportCallTable(tableOutput, errorOutput, namelessModules); -//// } catch (ParserConfigurationException | SAXException e) { -//// FxcaMain.LOGGER.error("Call table export failed: {}", e.getLocalizedMessage()); -//// } -// -// operationListOutput.close(); -// tableOutput.close(); -// errorOutput.close(); -// } catch (final IOException e) { -// FxcaMain.LOGGER.error("Cannot write {} file: {}", FxcaMain.OPERATION_DEFINITIONS, e.getLocalizedMessage()); -// } -// } - @Override protected TeetimeConfiguration createTeetimeConfiguration() throws ConfigurationException { return new TeetimeConfiguration(this.settings); diff --git a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/TeetimeConfiguration.java b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/TeetimeConfiguration.java index 71883b873684c14b66adff1f7ca2806a16d2227d..14759052c73aa3873b380eb9a51038e5fc7477fc 100644 --- a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/TeetimeConfiguration.java +++ b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/TeetimeConfiguration.java @@ -16,11 +16,15 @@ package org.oceandsl.tools.fxca; import teetime.framework.Configuration; +import teetime.stage.basic.distributor.Distributor; +import teetime.stage.basic.distributor.strategy.CopyByReferenceStrategy; import org.oceandsl.analysis.generic.stages.DirectoryProducer; import org.oceandsl.analysis.generic.stages.DirectoryScannerStage; import org.oceandsl.analysis.generic.stages.TableCSVSink; -import org.oceandsl.tools.fxca.stages.ComputeOutputState; +import org.oceandsl.tools.fxca.model.FortranProject; +import org.oceandsl.tools.fxca.stages.CreateCallTableStage; +import org.oceandsl.tools.fxca.stages.CreateOperationTableStage; import org.oceandsl.tools.fxca.stages.ProcessModuleStructureStage; import org.oceandsl.tools.fxca.stages.ProcessOperationCallStage; import org.oceandsl.tools.fxca.stages.ReadDomStage; @@ -44,20 +48,32 @@ public class TeetimeConfiguration extends Configuration { final ReadDomStage readDomStage = new ReadDomStage(); final ProcessModuleStructureStage processModuleStructureStage = new ProcessModuleStructureStage(); final ProcessOperationCallStage processOperationCallStage = new ProcessOperationCallStage(); - final ComputeOutputState computeOutputStage = new ComputeOutputState(); + + final Distributor<FortranProject> projectDistributor = new Distributor<>(new CopyByReferenceStrategy()); + + final CreateCallTableStage callTableStage = new CreateCallTableStage(); + final CreateOperationTableStage operationTableStage = new CreateOperationTableStage(); /** output stages */ - final TableCSVSink operationDefinitionsSink = new TableCSVSink( + final TableCSVSink operationTableSink = new TableCSVSink( o -> settings.getOutputDirectoryPath().resolve(TeetimeConfiguration.OPERATION_DEFINITIONS), true); final TableCSVSink callTableSink = new TableCSVSink( o -> settings.getOutputDirectoryPath().resolve(TeetimeConfiguration.CALL_TABLE), true); - final TableCSVSink notoundSink = new TableCSVSink( + final TableCSVSink notFoundSink = new TableCSVSink( o -> settings.getOutputDirectoryPath().resolve(TeetimeConfiguration.NOT_FOUND), true); this.connectPorts(producer.getOutputPort(), directoryScannerStage.getInputPort()); this.connectPorts(directoryScannerStage.getOutputPort(), readDomStage.getInputPort()); this.connectPorts(readDomStage.getOutputPort(), processModuleStructureStage.getInputPort()); this.connectPorts(processModuleStructureStage.getOutputPort(), processOperationCallStage.getInputPort()); - this.connectPorts(processOperationCallStage.getOutputPort(), computeOutputStage.getInputPort()); + + this.connectPorts(processOperationCallStage.getOutputPort(), projectDistributor.getInputPort()); + this.connectPorts(processOperationCallStage.getNotFoundOutputPort(), notFoundSink.getInputPort()); + + this.connectPorts(projectDistributor.getNewOutputPort(), callTableStage.getInputPort()); + this.connectPorts(callTableStage.getOutputPort(), callTableSink.getInputPort()); + + this.connectPorts(projectDistributor.getNewOutputPort(), operationTableStage.getInputPort()); + this.connectPorts(operationTableStage.getOutputPort(), operationTableSink.getInputPort()); } } diff --git a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/CallTableStage.java b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/CallTableStage.java deleted file mode 100644 index dc73a23a3034ebd3d14971eb7a850256805217dd..0000000000000000000000000000000000000000 --- a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/CallTableStage.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.oceandsl.tools.fxca.stages; - -import java.io.IOException; -import java.io.PrintStream; -import java.util.List; - -import javax.xml.parsers.ParserConfigurationException; - -import org.xml.sax.SAXException; - -import teetime.stage.basic.AbstractTransformation; - -import org.oceandsl.analysis.code.stages.data.Table; -import org.oceandsl.tools.fxca.model.FortranModule; -import org.oceandsl.tools.fxca.model.FortranProject; -import org.oceandsl.tools.fxca.tools.ListTools; -import org.oceandsl.tools.fxca.tools.Pair; - -/** - * - * @author Henning Schnoor -- initial contribution - * @author Reiner Jung - * - */ -public class CallTableStage extends AbstractTransformation<FortranProject, Table> { - - @Override - protected void execute(final FortranProject element) throws Exception { - // TODO Auto-generated method stub - - } - - /** - * Exports the call cable into CSV files. - * - * @param PrintStream - * for table - * @param PrintStream - * for list of not-found entries - * @param globalModules - * list of modules that are available to all modules / files without explicit - * reference - * @throws ParserConfigurationException - * @throws SAXException - * @throws IOException - */ - private void exportCallTable(final PrintStream tableOut, final PrintStream notFoundOut, - final List<FortranModule> globalModules) throws ParserConfigurationException, SAXException, IOException { - tableOut.println("callerfilename,callermodule,callerfunction,calleefilename,calleemodule,calleefunction"); - this.logger.debug("Calls to operations that could not be found:"); - for (final FortranModule module : globalModules) { - for (final Pair<String, String> call : module.operationCalls()) { - final String callerFunctionName = call.first; - final String callerFileName = module.getXmlFilePath().toAbsolutePath().getFileName().toString(); - final String calleeFunctionName = call.second; - final FortranModule calleeXML = this.resolveCallee(module, calleeFunctionName, globalModules); - final String calleeFileName = calleeXML == null ? "<unknown>" - : calleeXML.getXmlFilePath().toAbsolutePath().getFileName().toString(); - final String calleeModuleName = calleeXML == null ? "<unknown>" : calleeXML.getModuleName(); - tableOut.println(callerFileName + ", " + module.getModuleName() + ", " + callerFunctionName + ", " - + calleeFileName + ", " + calleeModuleName + ", " + calleeFunctionName); - if (calleeXML == null) { - notFoundOut.println(callerFileName + ":" + callerFunctionName + " --> " + calleeFunctionName); - } - } - } - } - - private FortranModule resolveCallee(final FortranModule xml, final String calleeFunctionName, - final List<FortranModule> globalModules) { - this.logger.debug("resolve Callee: {} from {}", calleeFunctionName, xml.getXmlFilePath()); - /* - * if ("MDS_WRITE_FIELD".equals(calleeFunctionName)) { System.exit(0); } - */ - return ListTools.getUniqueElementIfNonEmpty( - this.resolveCalleeModuleCandidates(xml, calleeFunctionName, globalModules), null); - } - - private List<FortranModule> resolveCalleeModuleCandidates(final FortranModule callerModule, - final String calleeOperationName, final List<FortranModule> globalModules) { - - final List<FortranModule> result = ListTools.ofM(); - final List<FortranModule> usedModules = ListTools.ofM(callerModule); // local definitions - // are always the first - // ones. - - for (final String usedModuleName : callerModule.getUsedModules()) { - // final FortranModule moduleXML = moduleNames.get(usedModuleName); -// if (moduleXML == null) { -// this.logger.warn("MODULE NOT FOUND: [{}]", usedModuleName); -// } else { -// usedModules.add(moduleXML); -// } - } - - if (globalModules != null) { - usedModules.addAll(globalModules); - } - - for (final FortranModule usedModule : usedModules) { - if (usedModule.getSpecifiedOperations().contains(calleeOperationName)) { - result.add(usedModule); - } - } - return result; - } - -} diff --git a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/ComputeOutputState.java b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/ComputeOutputState.java deleted file mode 100644 index 2ef5c99a68d38d65b881ce38f8680fa6f6aa4344..0000000000000000000000000000000000000000 --- a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/ComputeOutputState.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.oceandsl.tools.fxca.stages; - -import teetime.framework.AbstractConsumerStage; -import teetime.framework.OutputPort; - -import org.oceandsl.analysis.code.stages.data.StringValueHandler; -import org.oceandsl.analysis.code.stages.data.Table; -import org.oceandsl.analysis.code.stages.data.ValueConversionErrorException; -import org.oceandsl.tools.fxca.model.FortranModule; -import org.oceandsl.tools.fxca.model.FortranProject; -import org.oceandsl.tools.fxca.tools.Pair; - -public class ComputeOutputState extends AbstractConsumerStage<FortranProject> { - - private static final String SOURCE_PATH = "callerfilename"; - private static final String SOURCE_MODULE = "callermodule"; - private static final String SOURCE_OPERATION = "callerfunction"; - private static final String TARGET_PATH = "calleefilename"; - private static final String TARGET_MODULE = "calleemodule"; - private static final String TARGET_OPERATION = "calleefunction"; - - private final OutputPort<Table> callsOutputPort = this.createOutputPort(Table.class); - private final OutputPort<Table> callTableOutputPort = this.createOutputPort(Table.class); - private final OutputPort<Table> notFoundOutputPort = this.createOutputPort(Table.class); - - @Override - protected void execute(final FortranProject project) throws Exception { - final Table callsTable = new Table("calls", new StringValueHandler(SOURCE_PATH), - new StringValueHandler(SOURCE_MODULE), new StringValueHandler(SOURCE_OPERATION), - new StringValueHandler(TARGET_PATH), new StringValueHandler(TARGET_MODULE), - new StringValueHandler(TARGET_OPERATION)); - project.getModules().values().forEach(module -> { - module.getCalls().forEach(call -> { - final Pair<FortranModule, String> caller = call.getFirst(); - final Pair<FortranModule, String> callee = call.getSecond(); - - if (caller != null) { - final FortranModule callerModule = caller.getFirst(); - - final String callerPath; - final String callerModuleName; - final String callerOperation = caller.getSecond(); - - if (callerModule.isNamedModule()) { - callerPath = callerModule.getDocument().getBaseURI(); - callerModuleName = callerModule.getModuleName(); - } else { - callerPath = callerModule.getModuleName(); - callerModuleName = "<no-module>"; - } - - if (callee != null) { - final FortranModule calleeModule = callee.getFirst(); - - final String calleePath; - final String calleeModuleName; - final String calleeOperation = callee.getSecond(); - - if (calleeModule.isNamedModule()) { - calleePath = calleeModule.getDocument().getBaseURI(); - calleeModuleName = calleeModule.getModuleName(); - } else { - calleePath = calleeModule.getModuleName(); - calleeModuleName = "<no-module>"; - } - try { - callsTable.addRow(callerPath, callerModuleName, callerOperation, calleePath, - calleeModuleName, calleeOperation); - } catch (final ValueConversionErrorException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } else { - this.logger.debug("Caller {} {} {} has no callee ", callerPath, callerModuleName, - callerOperation); - } - } else { - if (callee != null) { - final FortranModule calleeModule = callee.getFirst(); - - final String calleePath; - final String calleeModuleName; - final String calleeOperation = callee.getSecond(); - - if (calleeModule.isNamedModule()) { - calleePath = calleeModule.getDocument().getBaseURI(); - calleeModuleName = calleeModule.getModuleName(); - } else { - calleePath = calleeModule.getModuleName(); - calleeModuleName = "<no-module>"; - } - - this.logger.debug("No caller for callee {} {} {}", calleePath, calleeModuleName, - calleeOperation); - } else { - this.logger.debug("Empty call"); - } - } - }); - }); - - this.callsOutputPort.send(callsTable); - } - -} diff --git a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/CreateCallTableStage.java b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/CreateCallTableStage.java new file mode 100644 index 0000000000000000000000000000000000000000..7b9ea393de1e0f15cca4f71ce2eec1038ca8702a --- /dev/null +++ b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/CreateCallTableStage.java @@ -0,0 +1,90 @@ +package org.oceandsl.tools.fxca.stages; + +import teetime.stage.basic.AbstractTransformation; + +import org.oceandsl.analysis.code.stages.data.StringValueHandler; +import org.oceandsl.analysis.code.stages.data.Table; +import org.oceandsl.analysis.code.stages.data.ValueConversionErrorException; +import org.oceandsl.tools.fxca.model.FortranModule; +import org.oceandsl.tools.fxca.model.FortranProject; +import org.oceandsl.tools.fxca.tools.Pair; + +public class CreateCallTableStage extends AbstractTransformation<FortranProject, Table> { + + private static final String SOURCE_PATH = "callerfilename"; + private static final String SOURCE_MODULE = "callermodule"; + private static final String SOURCE_OPERATION = "callerfunction"; + private static final String TARGET_PATH = "calleefilename"; + private static final String TARGET_MODULE = "calleemodule"; + private static final String TARGET_OPERATION = "calleefunction"; + + private record Operation(String path, String moduleName, String operation) { + Operation(final String path, final String moduleName, final String operation) { + this.path = path; + this.moduleName = moduleName; + this.operation = operation; + } + } + + @Override + protected void execute(final FortranProject project) throws Exception { + final Table callsTable = new Table("calls", new StringValueHandler(CreateCallTableStage.SOURCE_PATH), + new StringValueHandler(CreateCallTableStage.SOURCE_MODULE), + new StringValueHandler(CreateCallTableStage.SOURCE_OPERATION), + new StringValueHandler(CreateCallTableStage.TARGET_PATH), + new StringValueHandler(CreateCallTableStage.TARGET_MODULE), + new StringValueHandler(CreateCallTableStage.TARGET_OPERATION)); + + final Table notFound = new Table("not-found", new StringValueHandler(CreateCallTableStage.SOURCE_PATH), + new StringValueHandler(CreateCallTableStage.SOURCE_MODULE), + new StringValueHandler(CreateCallTableStage.SOURCE_OPERATION), + new StringValueHandler(CreateCallTableStage.TARGET_OPERATION)); + + project.getModules().values().forEach(module -> { + module.getCalls().forEach(call -> { + final Pair<FortranModule, String> callerPair = call.getFirst(); + final Pair<FortranModule, String> calleePair = call.getSecond(); + + if (callerPair != null) { + final Operation caller = this.composeOperation(callerPair); + if (calleePair != null) { + final Operation callee = this.composeOperation(calleePair); + try { + callsTable.addRow(caller.path, caller.moduleName, caller.operation, callee.path, + callee.moduleName, callee.operation); + } catch (final ValueConversionErrorException e) { + this.logger.error("Error writing calls to table: {}", e.getLocalizedMessage()); + } + } else { + this.logger.warn("Caller {} {} {} has no callee ", caller.path, caller.moduleName, + caller.operation); + } + } else { + if (calleePair != null) { + final Operation callee = this.composeOperation(calleePair); + this.logger.warn("No caller for callee {} {} {}", callee.path, callee.moduleName, + callee.operation); + } else { + this.logger.error("Empty call"); + } + } + }); + }); + + this.outputPort.send(callsTable); + } + + private Operation composeOperation(final Pair<FortranModule, String> operationDescription) { + final FortranModule module = operationDescription.getFirst(); + + final String callerOperation = operationDescription.getSecond(); + + if (module.isNamedModule()) { + return new Operation(module.getDocument().getBaseURI(), module.getModuleName(), callerOperation); + } else { + return new Operation(module.getDocument().getBaseURI(), "<no-module>", callerOperation); + } + + } + +} diff --git a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/CreateOperationTableStage.java b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/CreateOperationTableStage.java new file mode 100644 index 0000000000000000000000000000000000000000..b48123c3de4b6edebc3be2042018c79b702c2618 --- /dev/null +++ b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/CreateOperationTableStage.java @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2023 OceanDSL (https://oceandsl.uni-kiel.de) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ***************************************************************************/ +package org.oceandsl.tools.fxca.stages; + +import teetime.stage.basic.AbstractTransformation; + +import org.oceandsl.analysis.code.stages.data.StringValueHandler; +import org.oceandsl.analysis.code.stages.data.Table; +import org.oceandsl.analysis.code.stages.data.ValueConversionErrorException; +import org.oceandsl.tools.fxca.model.FortranProject; + +/** + * Create a table containing operations. + * + * @author Henning Schnoor -- initial contribution + * @author Reiner Jung + */ +public class CreateOperationTableStage extends AbstractTransformation<FortranProject, Table> { + + @Override + protected void execute(final FortranProject project) throws Exception { + final Table callsTable = new Table("operation", new StringValueHandler("file"), + new StringValueHandler("operation")); + project.getModules().values().forEach(module -> { + final String path = module.getDocument().getBaseURI(); + module.getSpecifiedOperations().forEach(operation -> { + try { + callsTable.addRow(path, operation); + } catch (final ValueConversionErrorException e) { + this.logger.error("Error writing values to operation table: {}", e.getLocalizedMessage()); + } + }); + }); + + this.outputPort.send(callsTable); + } + +} diff --git a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/ProcessModuleStructureStage.java b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/ProcessModuleStructureStage.java index c22728a234a6b5274a99aa7258decd0aafe81d8d..a1a35591663fc538e1bb397d9a94f8596a4bfa57 100644 --- a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/ProcessModuleStructureStage.java +++ b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/ProcessModuleStructureStage.java @@ -16,6 +16,7 @@ package org.oceandsl.tools.fxca.stages; import java.io.IOException; +import java.util.Locale; import java.util.Set; import javax.xml.parsers.ParserConfigurationException; @@ -29,8 +30,8 @@ import teetime.stage.basic.AbstractTransformation; import org.oceandsl.tools.fxca.model.FortranModule; import org.oceandsl.tools.fxca.model.FortranProject; -import org.oceandsl.tools.fxca.model.StatementNode; import org.oceandsl.tools.fxca.tools.ListTools; +import org.oceandsl.tools.fxca.tools.NodeProcessingUtils; /** * @@ -50,7 +51,7 @@ public class ProcessModuleStructureStage extends AbstractTransformation<Document protected void execute(final Document document) throws Exception { final Element documentElement = document.getDocumentElement(); final Node moduleStatement = ListTools.getUniqueElementIfNonEmpty( - StatementNode.allDescendents(documentElement, StatementNode.isModuleStatement, true), null); + NodeProcessingUtils.allDescendents(documentElement, NodeProcessingUtils.isModuleStatement, true), null); final boolean namedModule = moduleStatement != null; final String moduleName = namedModule ? moduleStatement.getChildNodes().item(1).getTextContent() @@ -71,7 +72,7 @@ public class ProcessModuleStructureStage extends AbstractTransformation<Document } private void computeUsedModels(final FortranModule module, final Element rootNode) { - final Set<Node> useStatements = StatementNode.allDescendents(rootNode, StatementNode.isUseStatement, false); + final Set<Node> useStatements = NodeProcessingUtils.allDescendents(rootNode, NodeProcessingUtils.isUseStatement, false); for (final Node useStatement : useStatements) { final String usedModuleName = useStatement.getChildNodes().item(1).getTextContent(); this.logger.debug("found use statement: {}, module name: {}", useStatement.getTextContent(), @@ -82,10 +83,10 @@ public class ProcessModuleStructureStage extends AbstractTransformation<Document public void computeOperationDeclarations(final FortranModule module, final Element documentElement) throws ParserConfigurationException, SAXException, IOException { - StatementNode - .getDescendentAttributes(documentElement, StatementNode.isOperationStatement, - operationNode -> StatementNode.getNameOfOperation(operationNode)) - .forEach(operation -> module.getSpecifiedOperations().add(operation)); + NodeProcessingUtils + .getDescendentAttributes(documentElement, NodeProcessingUtils.isOperationStatement, + operationNode -> NodeProcessingUtils.getNameOfOperation(operationNode)) + .forEach(operation -> module.getSpecifiedOperations().add(operation.toLowerCase(Locale.getDefault()))); } } diff --git a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/ProcessOperationCallStage.java b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/ProcessOperationCallStage.java index 1b6e92250782d1c82f4eadbbfc597f9d18f35c43..0216d7f5f5a83533309d7514ef68ddceeb02fe83 100644 --- a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/ProcessOperationCallStage.java +++ b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/stages/ProcessOperationCallStage.java @@ -25,11 +25,15 @@ import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Element; import org.xml.sax.SAXException; +import teetime.framework.OutputPort; import teetime.stage.basic.AbstractFilter; +import org.oceandsl.analysis.code.stages.data.StringValueHandler; +import org.oceandsl.analysis.code.stages.data.Table; +import org.oceandsl.analysis.code.stages.data.ValueConversionErrorException; import org.oceandsl.tools.fxca.model.FortranModule; import org.oceandsl.tools.fxca.model.FortranProject; -import org.oceandsl.tools.fxca.model.StatementNode; +import org.oceandsl.tools.fxca.tools.NodeProcessingUtils; import org.oceandsl.tools.fxca.tools.Pair; /** @@ -39,32 +43,72 @@ import org.oceandsl.tools.fxca.tools.Pair; */ public class ProcessOperationCallStage extends AbstractFilter<FortranProject> { + private final OutputPort<Table> notFoundOutputPort = this.createOutputPort(Table.class); + @Override protected void execute(final FortranProject project) throws Exception { + final Table notFoundTable = new Table("not-found", new StringValueHandler("caller-path"), + new StringValueHandler("caller-module"), new StringValueHandler("caller-operation"), + new StringValueHandler("callee-operation")); + project.getModules().values().forEach(module -> { final Element element = module.getDocument().getDocumentElement(); - try { - final List<Pair<String, String>> calls = StatementNode.subroutineCalls(element); - calls.forEach(call -> { - final Pair<FortranModule, String> caller = this.findOperation(project.getModules().values(), - call.getFirst()); - final Pair<FortranModule, String> callee = this.findOperation(project.getModules().values(), - call.getSecond()); - if (caller == null) { - this.logger.debug("Caller not found for {}", call.getFirst()); - } - if (callee == null) { - this.logger.debug("Callee not found for {}", call.getSecond()); - } - module.getCalls().add(new Pair<>(caller, callee)); - }); - } catch (ParserConfigurationException | SAXException | IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + this.processSubroutines(project, module, element, notFoundTable); + this.processFunctions(project, module, element, notFoundTable); }); this.outputPort.send(project); + this.notFoundOutputPort.send(notFoundTable); + } + + private void processSubroutines(final FortranProject project, final FortranModule module, final Element element, + final Table notFoundTable) { + try { + final List<Pair<String, String>> calls = NodeProcessingUtils.subroutineCalls(element); + this.processCalls(project, module, calls, notFoundTable); + } catch (ParserConfigurationException | SAXException | IOException e) { + this.logger.error("Processing subroutine calls in file {} failed: {}", element.getBaseURI(), + e.getLocalizedMessage()); + } + } + + private void processFunctions(final FortranProject project, final FortranModule module, final Element element, + final Table notFoundTable) { + try { + final List<Pair<String, String>> calls = NodeProcessingUtils.functionCalls(element); + this.processCalls(project, module, calls, notFoundTable); + } catch (ParserConfigurationException | SAXException | IOException e) { + this.logger.error("Processing subroutine calls in file {} failed: {}", element.getBaseURI(), + e.getLocalizedMessage()); + } + + } + + private void processCalls(final FortranProject project, final FortranModule module, + final List<Pair<String, String>> calls, final Table notFoundTable) { + calls.forEach(call -> { + final Pair<FortranModule, String> caller = this.findOperation(project.getModules().values(), + call.getFirst()); + final Pair<FortranModule, String> callee = this.findOperation(project.getModules().values(), + call.getSecond()); + if (caller == null) { + this.logger.info("Caller not found for {}", call.getFirst()); + } + if (callee == null) { + try { + notFoundTable.addRow(caller.first.getDocument().getBaseURI(), caller.first.getModuleName(), + caller.second, call.second); + } catch (final ValueConversionErrorException e) { + this.logger.error("Cannot add row to callee not found table: {}", e.getLocalizedMessage()); + } + this.logger.info("Callee not found for {}", call.getSecond()); + } + module.getCalls().add(new Pair<>(caller, callee)); + }); + } + + public OutputPort<Table> getNotFoundOutputPort() { + return this.notFoundOutputPort; } private Pair<FortranModule, String> findOperation(final Collection<FortranModule> modules, final String signature) { diff --git a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/model/LocalExpressionAccess.java b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/tools/LocalExpressionAccess.java similarity index 76% rename from tools/fxca/src/main/java/org/oceandsl/tools/fxca/model/LocalExpressionAccess.java rename to tools/fxca/src/main/java/org/oceandsl/tools/fxca/tools/LocalExpressionAccess.java index 76f603c8a2a3ae99817a1519b46c8d4d65c41b8d..ca9a1982319d5069ee8a42d98b400c8f51746ef6 100644 --- a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/model/LocalExpressionAccess.java +++ b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/tools/LocalExpressionAccess.java @@ -1,4 +1,4 @@ -package org.oceandsl.tools.fxca.model; +package org.oceandsl.tools.fxca.tools; import java.util.ArrayList; import java.util.Collection; @@ -30,17 +30,17 @@ public class LocalExpressionAccess { COMMON_BLOCK, LOCAL_VARIABLE, OPERATION_PARAMETER, OPERATION_CALL } - static LocalAccessParameters namesInCommonBlocks = new LocalAccessParameters(StatementNode.isCommonStatement, - StatementNode.isCommonBlockObjectStatement, StatementNode.isSmallN, - smallNNode -> StatementNode.getSuccessorNode(smallNNode, "0").getTextContent()); + static LocalAccessParameters namesInCommonBlocks = new LocalAccessParameters(NodeProcessingUtils.isCommonStatement, + NodeProcessingUtils.isCommonBlockObjectStatement, NodeProcessingUtils.isSmallN, + smallNNode -> NodeProcessingUtils.getSuccessorNode(smallNNode, "0").getTextContent()); static LocalAccessParameters namesInOperationParameterList = new LocalAccessParameters( - StatementNode.isOperationStatement, StatementNode.isArgN, StatementNode.isSmallN, - smallNNode -> StatementNode.getSuccessorNode(smallNNode, "0").getTextContent()); + NodeProcessingUtils.isOperationStatement, NodeProcessingUtils.isArgN, NodeProcessingUtils.isSmallN, + smallNNode -> NodeProcessingUtils.getSuccessorNode(smallNNode, "0").getTextContent()); - static LocalAccessParameters namesInLocalVariableList = new LocalAccessParameters(StatementNode.isTDeclStmt, - StatementNode.isEnDcl, StatementNode.isSmallN, - smallNNode -> StatementNode.getSuccessorNode(smallNNode, "0").getTextContent()); + static LocalAccessParameters namesInLocalVariableList = new LocalAccessParameters(NodeProcessingUtils.isTDeclStmt, + NodeProcessingUtils.isEnDcl, NodeProcessingUtils.isSmallN, + smallNNode -> NodeProcessingUtils.getSuccessorNode(smallNNode, "0").getTextContent()); static Set<String> localNamesDefinedInApplyingBlocks(final Node node, final LocalAccessParameters parameters, final boolean verbose) { @@ -50,9 +50,9 @@ public class LocalExpressionAccess { Node current = node; while (current != null) { - final List<Node> applyingBlocksOnThisLevel = StatementNode.findAll(current, + final List<Node> applyingBlocksOnThisLevel = NodeProcessingUtils.findAll(current, nnode -> nnode.getPreviousSibling(), parameters.blockNodeTypeCheckPredicate, true, - StatementNode.paranthesisTypes, -1); + NodeProcessingUtils.paranthesisTypes, -1); applyingBlocks.addAll(applyingBlocksOnThisLevel); current = current.getParentNode(); } @@ -78,8 +78,8 @@ public class LocalExpressionAccess { } final HashSet<String> result = new HashSet<>(); - for (final Node element : StatementNode.allDescendents(blockNode, parameters.outerDelimiterPredicate, true)) { - for (final Node smallN : StatementNode.allDescendents(element, parameters.innerDelimiterPredicate, true)) { + for (final Node element : NodeProcessingUtils.allDescendents(blockNode, parameters.outerDelimiterPredicate, true)) { + for (final Node smallN : NodeProcessingUtils.allDescendents(element, parameters.innerDelimiterPredicate, true)) { result.add(parameters.extractName.apply(smallN)); } } @@ -89,11 +89,11 @@ public class LocalExpressionAccess { public static boolean isNamedExpressionLocalReference(final Node node, final LocalAccessParameters parameters) { - if (!StatementNode.namedExpressionAccess.test(node)) { + if (!NodeProcessingUtils.namedExpressionAccess.test(node)) { return false; } - final String nameOfCalledFunction = StatementNode.nameOfCalledFunction(node); + final String nameOfCalledFunction = NodeProcessingUtils.nameOfCalledFunction(node); return LocalExpressionAccess.localNamesDefinedInApplyingBlocks(node, parameters, false) .contains(nameOfCalledFunction); @@ -117,7 +117,7 @@ public class LocalExpressionAccess { } public static boolean isLocalAccess(final Node referenceNode) { - return StatementNode.isCallStatement.or(StatementNode.namedExpressionAccess).test(referenceNode) + return NodeProcessingUtils.isCallStatement.or(NodeProcessingUtils.namedExpressionAccess).test(referenceNode) && typeOfReferenceAccess(referenceNode) != accessType.OPERATION_CALL; } @@ -156,7 +156,7 @@ public class LocalExpressionAccess { throw new IllegalStateException(); } - return StatementNode.nameOfCalledFunction(referenceNode) + suffix; + return NodeProcessingUtils.nameOfCalledFunction(referenceNode) + suffix; } } diff --git a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/model/StatementNode.java b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/tools/NodeProcessingUtils.java similarity index 58% rename from tools/fxca/src/main/java/org/oceandsl/tools/fxca/model/StatementNode.java rename to tools/fxca/src/main/java/org/oceandsl/tools/fxca/tools/NodeProcessingUtils.java index 59ebb747c24b82e649aba46a09525894f4ac6f63..03bd1e5682a1e66b884474032cf7faef12a7fb41 100644 --- a/tools/fxca/src/main/java/org/oceandsl/tools/fxca/model/StatementNode.java +++ b/tools/fxca/src/main/java/org/oceandsl/tools/fxca/tools/NodeProcessingUtils.java @@ -13,13 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. ***************************************************************************/ -package org.oceandsl.tools.fxca.model; +package org.oceandsl.tools.fxca.tools; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; @@ -32,9 +33,6 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; -import org.oceandsl.tools.fxca.tools.ListTools; -import org.oceandsl.tools.fxca.tools.Pair; - // No own attributes, only accessor functions for nodes. Implemented as class in order to allow // chaining. @@ -43,60 +41,79 @@ import org.oceandsl.tools.fxca.tools.Pair; * @author Henning Schnoor * @since 1.3.0 */ -public class StatementNode { - - public static Predicate<Node> isSubroutineStatement = StatementNode.hasName("subroutine-stmt"); - public static Predicate<Node> isEndSubroutineStatement = StatementNode.hasName("end-subroutine-stmt"); - public static Predicate<Node> isFunctionStatement = StatementNode.hasName("function-stmt"); - public static Predicate<Node> isOperationStatement = StatementNode.isSubroutineStatement - .or(StatementNode.isFunctionStatement); - public static Predicate<Node> isEndFunctionStatement = StatementNode.hasName("end-function-stmt"); - public static Predicate<Node> isModuleStatement = StatementNode.hasName("module-stmt"); - public static Predicate<Node> isUseStatement = StatementNode.hasName("use-stmt"); - public static Predicate<Node> isCallStatement = StatementNode.hasName("call-stmt"); - public static Predicate<Node> isSubroutineName = StatementNode.hasName("subroutine-N"); - public static Predicate<Node> isFunctionName = StatementNode.hasName("function-N"); - public static Predicate<Node> isNamedExpression = StatementNode.hasName("named-E"); - public static Predicate<Node> isBigN = StatementNode.hasName("N"); - public static Predicate<Node> isArgN = StatementNode.hasName("arg-N"); - public static Predicate<Node> isTDeclStmt = StatementNode.hasName("T-decl-stmt"); - public static Predicate<Node> isEnDcl = StatementNode.hasName("EN-decl"); - public static Predicate<Node> isSmallN = StatementNode.hasName("n"); - public static Predicate<Node> isElementLT = StatementNode.hasName("element-LT"); - public static Predicate<Node> isRLT = StatementNode.hasName("R-LT"); - public static Predicate<Node> isElement = StatementNode.hasName("element"); - public static Predicate<Node> isParensR = StatementNode.hasName("parens-R"); - public static Predicate<Node> isRegularLeftParanthesis = StatementNode.isParensR +public class NodeProcessingUtils { + + public static Predicate<Node> isProgramStatement = NodeProcessingUtils.hasName("program-stmt"); + public static Predicate<Node> isSubroutineStatement = NodeProcessingUtils.hasName("subroutine-stmt"); + public static Predicate<Node> isFunctionStatement = NodeProcessingUtils.hasName("function-stmt"); + public static Predicate<Node> isEntryStatement = NodeProcessingUtils.hasName("entry-stmt"); + public static Predicate<Node> isOperationStatement = NodeProcessingUtils.isSubroutineStatement + .or(NodeProcessingUtils.isFunctionStatement).or(NodeProcessingUtils.isEntryStatement) + .or(NodeProcessingUtils.isProgramStatement); + + public static Predicate<Node> isEndSubroutineStatement = NodeProcessingUtils.hasName("end-subroutine-stmt"); + public static Predicate<Node> isEndFunctionStatement = NodeProcessingUtils.hasName("end-function-stmt"); + + public static Predicate<Node> isModuleStatement = NodeProcessingUtils.hasName("module-stmt"); + public static Predicate<Node> isUseStatement = NodeProcessingUtils.hasName("use-stmt"); + + public static Predicate<Node> isCallStatement = NodeProcessingUtils.hasName("call-stmt"); + + public static Predicate<Node> isProgramName = NodeProcessingUtils.hasName("program-N"); + public static Predicate<Node> isSubroutineName = NodeProcessingUtils.hasName("subroutine-N"); + public static Predicate<Node> isFunctionName = NodeProcessingUtils.hasName("function-N"); + public static Predicate<Node> isEntryName = NodeProcessingUtils.hasName("entry-N"); + + public static Predicate<Node> isNamedExpression = NodeProcessingUtils.hasName("named-E"); + public static Predicate<Node> isBigN = NodeProcessingUtils.hasName("N"); + public static Predicate<Node> isArgN = NodeProcessingUtils.hasName("arg-N"); + public static Predicate<Node> isTDeclStmt = NodeProcessingUtils.hasName("T-decl-stmt"); + public static Predicate<Node> isEnDcl = NodeProcessingUtils.hasName("EN-decl"); + public static Predicate<Node> isSmallN = NodeProcessingUtils.hasName("n"); + public static Predicate<Node> isElementLT = NodeProcessingUtils.hasName("element-LT"); + public static Predicate<Node> isRLT = NodeProcessingUtils.hasName("R-LT"); + public static Predicate<Node> isElement = NodeProcessingUtils.hasName("element"); + public static Predicate<Node> isParensR = NodeProcessingUtils.hasName("parens-R"); + public static Predicate<Node> isRegularLeftParanthesis = NodeProcessingUtils.isParensR .and(node -> node.getTextContent().startsWith("(")); - public static Predicate<Node> isCommonStatement = StatementNode.hasName("common-stmt"); - public static Predicate<Node> isCommonBlockObjectStatement = StatementNode.hasName("common-block-obj-N"); + public static Predicate<Node> isCommonStatement = NodeProcessingUtils.hasName("common-stmt"); + public static Predicate<Node> isCommonBlockObjectStatement = NodeProcessingUtils.hasName("common-block-obj-N"); public static Predicate<Node> isLocalAccess = node -> LocalExpressionAccess.isLocalAccess(node); - public static Predicate<Node> namedExpressionAccess = StatementNode.isNamedExpression - .and(StatementNode.childSatisfies("0", StatementNode.isBigN)) - .and(StatementNode.childSatisfies("0,0", StatementNode.isSmallN)) - .and(StatementNode.childSatisfies("1", StatementNode.isRLT)) - .and(StatementNode.childSatisfies("1,0", StatementNode.isRegularLeftParanthesis)); + public static Predicate<Node> namedExpressionAccess = NodeProcessingUtils.isNamedExpression + .and(NodeProcessingUtils.childSatisfies("0", NodeProcessingUtils.isBigN)) + .and(NodeProcessingUtils.childSatisfies("0,0", NodeProcessingUtils.isSmallN)) + .and(NodeProcessingUtils.childSatisfies("1", NodeProcessingUtils.isRLT)) + .and(NodeProcessingUtils.childSatisfies("1,0", NodeProcessingUtils.isRegularLeftParanthesis)); public static Pair<Predicate<Node>, Predicate<Node>> endFunctionToBeginFunction = new Pair<>( - StatementNode.isEndFunctionStatement, StatementNode.isFunctionStatement); + NodeProcessingUtils.isEndFunctionStatement, NodeProcessingUtils.isFunctionStatement); public static Pair<Predicate<Node>, Predicate<Node>> endSubroutineToBeginSubroutine = new Pair<>( - StatementNode.isEndSubroutineStatement, StatementNode.isSubroutineStatement); + NodeProcessingUtils.isEndSubroutineStatement, NodeProcessingUtils.isSubroutineStatement); public static List<Pair<Predicate<Node>, Predicate<Node>>> paranthesisTypes = List - .of(StatementNode.endFunctionToBeginFunction, StatementNode.endSubroutineToBeginSubroutine); + .of(NodeProcessingUtils.endFunctionToBeginFunction, NodeProcessingUtils.endSubroutineToBeginSubroutine); + + private static String ROOT_PROGRAM = "main"; + + /** methods. */ public static String nameOfCalledFunction(final Node functionCallNode) { - return StatementNode.getSuccessorNode(functionCallNode, "0,0").getTextContent(); + return NodeProcessingUtils.getSuccessorNode(functionCallNode, "0,0").getTextContent() + .toLowerCase(Locale.getDefault()); } public static String nameOfCalledOperation(final Node operationCallNode) { - return StatementNode.getSuccessorNode(operationCallNode, "1").getTextContent(); + return NodeProcessingUtils.getSuccessorNode(operationCallNode, "1").getTextContent() + .toLowerCase(Locale.getDefault()); } public static Predicate<Node> hasName(final String name) { - return node -> name.equals(node.getNodeName()); + return node -> { + System.err.println("---> " + node); + return name.equals(node.getNodeName()); + }; } public static Predicate<Node> hasTextContent(final String content) { @@ -104,7 +121,7 @@ public class StatementNode { } public static Predicate<Node> childSatisfies(final String path, final Predicate<Node> predicate) { - return node -> predicate.test(StatementNode.getSuccessorNode(node, path)); + return node -> predicate.test(NodeProcessingUtils.getSuccessorNode(node, path)); } public static String nodeType(final short nodeType) { @@ -133,7 +150,7 @@ public class StatementNode { spaces = spaces + " "; } int numberOfPrintedNodes = 1; - System.out.println(spaces + "[node type] " + StatementNode.nodeType(node.getNodeType())); + System.out.println(spaces + "[node type] " + NodeProcessingUtils.nodeType(node.getNodeType())); System.out.println(spaces + "[node name] " + node.getNodeName()); System.out.println(spaces + "[node value] " + node.getNodeValue()); System.out.println(spaces + "[node text content] " + node.getTextContent()); @@ -141,37 +158,11 @@ public class StatementNode { for (int i = 0; i < node.getChildNodes().getLength(); i++) { final Node child = node.getChildNodes().item(i); - numberOfPrintedNodes += StatementNode.printNode(child, depth + 1); + numberOfPrintedNodes += NodeProcessingUtils.printNode(child, depth + 1); } return numberOfPrintedNodes; } - // Node Search - - // private static boolean testNodeAndFirstChildPredicateChain(Node t, List<Predicate<Node>> - // predicates) { - // if (predicates.isEmpty()) { - // return true; - // } - // if (!predicates.get(0).test(t)) { - // return false; - // } - // if (predicates.size() == 1) { - // return true; - // } - // if (t.getChildNodes().getLength() == 0) { - // return false; - // } - // return testNodeAndFirstChildPredicateChain(t.getFirstChild(), predicates.subList(1, - // predicates.size())); - // } - - /* - * static private Predicate<Node> nodeAndfirstChildPredicateChain(List<Predicate<Node>> - * predicates) { return node -> testNodeAndFirstChildPredicateChain(node, predicates); } - */ - - // TODO this is not doing the right thing public static Node getSuccessorNode(final Node node, final String path) { final String firstNumber = StringUtils.substringBefore(path, ","); final String nextPath = StringUtils.substringAfter(path, ","); @@ -183,24 +174,14 @@ public class StatementNode { if (nextPath.isEmpty()) { return node.getChildNodes().item(childIndex); } else { - return StatementNode.getSuccessorNode(node.getChildNodes().item(childIndex), nextPath); + return NodeProcessingUtils.getSuccessorNode(node.getChildNodes().item(childIndex), nextPath); } } - /* - * private static ASTNode getFirstChildChain(Node node, int depth) { - * - * Node result = node; - * - * for (int i = 0; i < depth; i++) { result = result.getFirstChild(); } - * - * return new ASTNode(result); } - */ - // NOTE: Only terminates if nextNode eventually returns null or a matching element. private static Node findFirst(final Node parent, final Function<Node, Node> nextNode, final Predicate<Node> condition, final boolean includeSelf) { - return findFirst(parent, nextNode, condition, includeSelf, null); + return NodeProcessingUtils.findFirst(parent, nextNode, condition, includeSelf, null); } // paranthesistypes: contains pairs of "opening paranthesis" and "closed paranthesis" @@ -219,7 +200,8 @@ public class StatementNode { final Predicate<Node> condition, final boolean includeSelf, final List<Pair<Predicate<Node>, Predicate<Node>>> paranthesesTypes) { - final List<Node> result = findAll(parent, nextNode, condition, includeSelf, paranthesesTypes, 1); + final List<Node> result = NodeProcessingUtils.findAll(parent, nextNode, condition, includeSelf, + paranthesesTypes, 1); return result.isEmpty() ? null : result.get(0); } @@ -238,9 +220,9 @@ public class StatementNode { boolean inParanthesisInterval = false; // End if we do not have anywhere to search, or we have reached the limit (where "-1" counts // as "no limit"). - while (current != null && (result.size() < maxElementsToFind || maxElementsToFind == -1)) { + while ((current != null) && ((result.size() < maxElementsToFind) || (maxElementsToFind == -1))) { - if (!inParanthesisInterval && condition.test(current) && (current != parent || includeSelf)) { + if (!inParanthesisInterval && condition.test(current) && ((current != parent) || includeSelf)) { result.add(current); } @@ -272,71 +254,76 @@ public class StatementNode { private static boolean hasConnectedWith(final Node parent, final Function<Node, Node> nextNode, final Predicate<Node> condition, final boolean includeSelf) { - return findFirst(parent, nextNode, condition, includeSelf) != null; + return NodeProcessingUtils.findFirst(parent, nextNode, condition, includeSelf) != null; } private static boolean hasLeftSibling(final Node parent, final Predicate<Node> condition, final boolean includeSelf) { - return hasConnectedWith(parent, node -> node.getPreviousSibling(), condition, includeSelf); + return NodeProcessingUtils.hasConnectedWith(parent, node -> node.getPreviousSibling(), condition, includeSelf); } private static Node firstLeftSibling(final Node parent, final Predicate<Node> condition, final boolean includeSelf, final List<Pair<Predicate<Node>, Predicate<Node>>> paranthesisTypes) { - return findFirst(parent, node -> node.getPreviousSibling(), condition, includeSelf, paranthesisTypes); + return NodeProcessingUtils.findFirst(parent, node -> node.getPreviousSibling(), condition, includeSelf, + paranthesisTypes); } private static Node firstAncestor(final Node parent, final Predicate<Node> condition, final boolean includeSelf) { - return findFirst(parent, node -> node.getParentNode(), condition, includeSelf); + return NodeProcessingUtils.findFirst(parent, node -> node.getParentNode(), condition, includeSelf); } public static Set<Node> allDescendents(final Node node, final Predicate<Node> condition, final boolean includeSelf) { - return addAllDescendentsTo(node, condition, includeSelf, new HashSet<>()); + return NodeProcessingUtils.addAllDescendentsTo(node, condition, includeSelf, new HashSet<>()); } private static <T extends Collection<Node>> T addAllDescendentsTo(final Node node, final Predicate<Node> condition, final boolean includeSelf, final T addToThese) { - + System.err.println(">>> " + node); if (condition.test(node) && includeSelf) { addToThese.add(node); } for (int i = 0; i < node.getChildNodes().getLength(); i++) { final Node child = node.getChildNodes().item(i); - addAllDescendentsTo(child, condition, true, addToThese); + NodeProcessingUtils.addAllDescendentsTo(child, condition, true, addToThese); } return addToThese; } public static String getNameOfOperation(final Node operationStatement) { - - if (StatementNode.isSubroutineStatement.test(operationStatement)) { - return StatementNode.getNameOfOperation(operationStatement, StatementNode.isSubroutineName); - } else if (StatementNode.isFunctionStatement.test(operationStatement)) { - return StatementNode.getNameOfOperation(operationStatement, StatementNode.isFunctionName); + if (NodeProcessingUtils.isSubroutineStatement.test(operationStatement)) { + return NodeProcessingUtils.getNameOfOperation(operationStatement, NodeProcessingUtils.isSubroutineName); + } else if (NodeProcessingUtils.isFunctionStatement.test(operationStatement)) { + return NodeProcessingUtils.getNameOfOperation(operationStatement, NodeProcessingUtils.isFunctionName); + } else if (NodeProcessingUtils.isEntryStatement.test(operationStatement)) { + return NodeProcessingUtils.getNameOfOperation(operationStatement, NodeProcessingUtils.isEntryName); + } else if (NodeProcessingUtils.isProgramStatement.test(operationStatement)) { + return NodeProcessingUtils.ROOT_PROGRAM; } throw new IllegalArgumentException("Node is neither a function nor a subroutine statement."); } public static String getNameOfOperation(final Node operationStatement, final Predicate<Node> namePredicate) { - final Set<Node> nameNodes = allDescendents(operationStatement, namePredicate, true); - return ListTools.getUniqueElement(nameNodes).getTextContent(); + final Set<Node> nameNodes = NodeProcessingUtils.allDescendents(operationStatement, namePredicate, true); + return ListTools.getUniqueElement(nameNodes).getTextContent().toLowerCase(Locale.getDefault()); } public static <T> Set<T> getDescendentAttributes(final Node node, final Predicate<Node> predicate, final Function<Node, T> extractAttribute) throws ParserConfigurationException, SAXException, IOException { - return allDescendents(node, predicate, true).stream().map(extractAttribute).collect(Collectors.toSet()); + return NodeProcessingUtils.allDescendents(node, predicate, true).stream().map(extractAttribute) + .collect(Collectors.toSet()); } public static List<Pair<String, String>> operationCalls(final Node node, final Predicate<Node> callPredicate, final Function<Node, String> calledOperation) { final Set<Pair<String, String>> result = new HashSet<>(); // Check for double entries - final Set<Node> callStatements = allDescendents(node, callPredicate, true); + final Set<Node> callStatements = NodeProcessingUtils.allDescendents(node, callPredicate, true); for (final Node callStatement : callStatements) { final String callee = calledOperation.apply(callStatement); - final String caller = getNameOfContainingOperation(callStatement); + final String caller = NodeProcessingUtils.getNameOfContainingOperation(callStatement); result.add(new Pair<>(caller, callee)); } @@ -345,41 +332,44 @@ public class StatementNode { public static List<Pair<String, String>> subroutineCalls(final Node node) throws ParserConfigurationException, SAXException, IOException { - return operationCalls(node, StatementNode.isCallStatement.and(StatementNode.isLocalAccess.negate()), - subroutineCall -> StatementNode.nameOfCalledOperation(subroutineCall)); + return NodeProcessingUtils.operationCalls(node, + NodeProcessingUtils.isCallStatement.and(NodeProcessingUtils.isLocalAccess.negate()), + subroutineCall -> NodeProcessingUtils.nameOfCalledOperation(subroutineCall)); } public static List<Pair<String, String>> functionCalls(final Node node) throws ParserConfigurationException, SAXException, IOException { - return operationCalls(node, StatementNode.namedExpressionAccess.and(StatementNode.isLocalAccess.negate()), - functionCall -> StatementNode.nameOfCalledFunction(functionCall)); + return NodeProcessingUtils.operationCalls(node, + NodeProcessingUtils.namedExpressionAccess.and(NodeProcessingUtils.isLocalAccess.negate()), + functionCall -> NodeProcessingUtils.nameOfCalledFunction(functionCall)); } /** ---------------------------------- */ public static Node findContainingStatement(final Node parent, final Predicate<Node> condition) { - return findContainingStatement(parent, condition, null); + return NodeProcessingUtils.findContainingStatement(parent, condition, null); } public static Node findContainingStatement(final Node parent, final Predicate<Node> condition, final List<Pair<Predicate<Node>, Predicate<Node>>> paranthesisTypes) { - final Predicate<Node> hasSuchANodeAsLeftSibling = node -> hasLeftSibling(node, condition, false); - final Node siblingOfSuchNode = firstAncestor(parent, hasSuchANodeAsLeftSibling, !condition.test(parent)); + final Predicate<Node> hasSuchANodeAsLeftSibling = node -> NodeProcessingUtils.hasLeftSibling(node, condition, + false); + final Node siblingOfSuchNode = NodeProcessingUtils.firstAncestor(parent, hasSuchANodeAsLeftSibling, + !condition.test(parent)); if (siblingOfSuchNode == null) { return null; } - return firstLeftSibling(siblingOfSuchNode, condition, true, paranthesisTypes); + return NodeProcessingUtils.firstLeftSibling(siblingOfSuchNode, condition, true, paranthesisTypes); } private static String getNameOfContainingOperation(final Node node) { - - final Node containingOperationStatement = findContainingStatement(node, StatementNode.isOperationStatement, - StatementNode.paranthesisTypes); - return containingOperationStatement == null ? "<root>" - : StatementNode.getNameOfOperation(containingOperationStatement); + final Node containingOperationStatement = NodeProcessingUtils.findContainingStatement(node, + NodeProcessingUtils.isOperationStatement, NodeProcessingUtils.paranthesisTypes); + return containingOperationStatement == null ? NodeProcessingUtils.ROOT_PROGRAM + : NodeProcessingUtils.getNameOfOperation(containingOperationStatement); } // We make some assumptions about the structure of the Fortran files (and the generated XML @@ -395,29 +385,29 @@ public class StatementNode { final short type = node.getNodeType(); - if (type == Node.TEXT_NODE && node.getChildNodes().getLength() > 0) { + if ((type == Node.TEXT_NODE) && (node.getChildNodes().getLength() > 0)) { throw new IllegalArgumentException("text node with children"); } - if ("call-stmt".equals(node.getNodeName()) && node.getChildNodes().getLength() < 2) { - StatementNode.printNode(node, 0); + if ("call-stmt".equals(node.getNodeName()) && (node.getChildNodes().getLength() < 2)) { + NodeProcessingUtils.printNode(node, 0); throw new IllegalArgumentException("call statement with < 2 children"); } - if (StatementNode.isNamedExpression.test(node)) { + if (NodeProcessingUtils.isNamedExpression.test(node)) { // NodeList children = node.getChildNodes(); final Node firstChild = node.getFirstChild(); final Node firstGrandChild = firstChild.getFirstChild(); - if (!StatementNode.isBigN.test(firstChild)) { + if (!NodeProcessingUtils.isBigN.test(firstChild)) { throw new IllegalArgumentException("named expression with unexpected type of first child."); } - if (!StatementNode.isSmallN.test(firstGrandChild)) { + if (!NodeProcessingUtils.isSmallN.test(firstGrandChild)) { throw new IllegalArgumentException("named expression with unexpected type of first grandchild."); } if (firstGrandChild.getChildNodes().getLength() > 1) { - StatementNode.printNode(firstGrandChild, 0); + NodeProcessingUtils.printNode(firstGrandChild, 0); throw new IllegalArgumentException( "named expression with unexpected chlildren length list of first grandchild."); } @@ -427,7 +417,7 @@ public class StatementNode { } public int getNumberOfDescendants(final Node parent, final boolean countSelf) { - return allDescendents(parent, node -> true, countSelf).size(); + return NodeProcessingUtils.allDescendents(parent, node -> true, countSelf).size(); } }