| package org.eclipse.photran.internal.core.model; |
| |
| import java.util.LinkedList; |
| |
| import org.eclipse.cdt.core.model.CModelException; |
| import org.eclipse.cdt.internal.core.model.Parent; |
| import org.eclipse.photran.internal.core.lexer.Token; |
| import org.eclipse.photran.internal.core.parser.ASTBlockDataSubprogramNode; |
| import org.eclipse.photran.internal.core.parser.ASTComponentDeclNode; |
| import org.eclipse.photran.internal.core.parser.ASTDataComponentDefStmtNode; |
| import org.eclipse.photran.internal.core.parser.ASTDerivedTypeDefNode; |
| import org.eclipse.photran.internal.core.parser.ASTErrorConstructNode; |
| import org.eclipse.photran.internal.core.parser.ASTErrorProgramUnitNode; |
| import org.eclipse.photran.internal.core.parser.ASTExternalNameListNode; |
| import org.eclipse.photran.internal.core.parser.ASTExternalStmtNode; |
| import org.eclipse.photran.internal.core.parser.ASTFunctionSubprogramNode; |
| import org.eclipse.photran.internal.core.parser.ASTGenericBindingNode; |
| import org.eclipse.photran.internal.core.parser.ASTGenericSpecNode; |
| import org.eclipse.photran.internal.core.parser.ASTInterfaceBlockNode; |
| import org.eclipse.photran.internal.core.parser.ASTInterfaceBodyNode; |
| import org.eclipse.photran.internal.core.parser.ASTIntrinsicListNode; |
| import org.eclipse.photran.internal.core.parser.ASTIntrinsicStmtNode; |
| import org.eclipse.photran.internal.core.parser.ASTMainProgramNode; |
| import org.eclipse.photran.internal.core.parser.ASTModuleNode; |
| import org.eclipse.photran.internal.core.parser.ASTModuleProcedureStmtNode; |
| import org.eclipse.photran.internal.core.parser.ASTNodeWithErrorRecoverySymbols; |
| import org.eclipse.photran.internal.core.parser.ASTProcedureNameListNode; |
| import org.eclipse.photran.internal.core.parser.ASTSpecificBindingNode; |
| import org.eclipse.photran.internal.core.parser.ASTStmtFunctionStmtNode; |
| import org.eclipse.photran.internal.core.parser.ASTSubmoduleNode; |
| import org.eclipse.photran.internal.core.parser.ASTSubroutineSubprogramNode; |
| import org.eclipse.photran.internal.core.parser.GenericASTVisitor; |
| import org.eclipse.photran.internal.core.parser.IASTListNode; |
| import org.eclipse.photran.internal.core.parser.IASTNode; |
| |
| /** |
| * THIS IS AN INTERNAL CLASS. |
| * <p> |
| * This AST visitor is used by the {@link FortranModelBuilder} to construct the C model of a |
| * particular file. |
| * <p> |
| * Internally, when this visitor encounters a program, module, function, or other entity that should |
| * be displayed in the model, it calls back to the {@link FortranModelBuilder} and asks it to add an |
| * appropriate node to the model (via {@link FortranModelBuilder#addF90Element(FortranElement)}). |
| * |
| * @author Jeff Overbey |
| */ |
| @SuppressWarnings("restriction") |
| public final class FortranModelBuildingVisitor extends GenericASTVisitor |
| { |
| // --INFRASTRUCTURE-------------------------------------------------- |
| |
| private org.eclipse.cdt.internal.core.model.TranslationUnit translationUnit; |
| |
| private FortranModelBuilder modelBuilder; |
| |
| public FortranModelBuildingVisitor( |
| org.eclipse.cdt.internal.core.model.TranslationUnit translationUnit, |
| FortranModelBuilder modelBuilder) |
| { |
| this.translationUnit = translationUnit; |
| this.modelBuilder = modelBuilder; |
| } |
| |
| private LinkedList<IASTNode> parentParseTreeNodeStack = new LinkedList<IASTNode>(); |
| |
| private LinkedList<FortranElement> parentElementStack = new LinkedList<FortranElement>(); |
| |
| private FortranElement errorElement = null; |
| |
| private Parent getCurrentParent() |
| { |
| if (parentElementStack.isEmpty()) |
| return translationUnit; |
| else |
| return (Parent)parentElementStack.getLast(); |
| } |
| |
| private boolean isCurrentParent(IASTNode node) |
| { |
| if (parentParseTreeNodeStack.isEmpty()) |
| return false; |
| else |
| return node == (IASTNode)parentParseTreeNodeStack.getLast(); |
| } |
| |
| private FortranElement getErrorElement() |
| { |
| if (errorElement == null) |
| { |
| errorElement = new FortranElement.ErrorNode(translationUnit, "Syntax Errors"); //$NON-NLS-1$ |
| addToModelNoChildren(errorElement); |
| } |
| |
| return errorElement; |
| } |
| |
| private void addToModel(IASTNode parseTreeNode, FortranElement element) |
| { |
| try |
| { |
| modelBuilder.addF90Element(element); |
| beginAddingChildrenFor(parseTreeNode, element); |
| } |
| catch (CModelException e) |
| { |
| ; |
| } |
| } |
| |
| private void addToModelNoChildren(FortranElement element) |
| { |
| try |
| { |
| modelBuilder.addF90Element(element); |
| } |
| catch (CModelException e) |
| { |
| ; |
| } |
| } |
| |
| private void beginAddingChildrenFor(IASTNode parseTreeNode, FortranElement element) |
| { |
| parentParseTreeNodeStack.addLast(parseTreeNode); |
| parentElementStack.addLast(element); |
| } |
| |
| private void doneAddingChildrenFor(IASTNode node) |
| { |
| if (isCurrentParent(node)) |
| { |
| parentParseTreeNodeStack.removeLast(); |
| parentElementStack.removeLast(); |
| } |
| } |
| |
| // --VISITOR METHODS------------------------------------------------- |
| |
| @Override public void visitASTNode(IASTNode node) |
| { |
| // beginAddingChildrenFor is called in addToModel |
| traverseChildren(node); |
| doneAddingChildrenFor(node); |
| } |
| |
| private <T extends FortranElement> T setPos(T element, IASTNode astNode) |
| { |
| return setPos(element, astNode, false); |
| } |
| |
| private <T extends FortranElement> T setPos(T element, IASTNode astNode, boolean setIdPos) |
| { |
| Token first = astNode.findFirstToken(); |
| Token last = astNode.findLastToken(); |
| if (first != null && last != null) |
| { |
| int offset = first.getFileOffset(); |
| int length = last.getFileOffset()+last.getLength()-offset; |
| if (setIdPos) |
| element.setIdPos(offset, length); |
| element.setPos(offset, length); |
| element.setLines(first.getLine(), last.getLine()); |
| } |
| return element; |
| } |
| |
| @Override public void visitASTErrorProgramUnitNode(ASTErrorProgramUnitNode node) |
| { |
| addToModelNoChildren(setPos(configureElement(new FortranElement.ErrorNode(getCurrentParent(), "Erroneous program unit - " + describeError(node)), node.getErrorToken()), node, true)); //$NON-NLS-1$ |
| addToModelNoChildren(configureElement(new FortranElement.ErrorNode(getErrorElement(), describeError(node)), node.getErrorToken())); |
| } |
| |
| @Override public void visitASTErrorConstructNode(ASTErrorConstructNode node) |
| { |
| addToModelNoChildren(setPos(configureElement(new FortranElement.ErrorNode(getCurrentParent(), "Unrecognized statement or construct - " + describeError(node)), node.getErrorToken()), node, true)); //$NON-NLS-1$ |
| addToModelNoChildren(configureElement(new FortranElement.ErrorNode(getErrorElement(), describeError(node)), node.getErrorToken())); |
| } |
| |
| private String describeError(ASTNodeWithErrorRecoverySymbols node) |
| { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("Unexpected "); //$NON-NLS-1$ |
| sb.append(node.getErrorToken()); |
| sb.append(" (line "); //$NON-NLS-1$ |
| sb.append(node.getErrorToken().getLine()); |
| sb.append(", column "); //$NON-NLS-1$ |
| sb.append(node.getErrorToken().getCol()); |
| sb.append("). Expected one of the following: "); //$NON-NLS-1$ |
| sb.append(node.describeTerminalsExpectedAtErrorPoint()); |
| return sb.toString(); |
| } |
| |
| @Override public void visitASTMainProgramNode(ASTMainProgramNode node) |
| { |
| Token token = node.getProgramStmt() == null |
| ? null |
| : node.getProgramStmt().getProgramName().getProgramName(); |
| addToModel(node, setPos(configureElement(new FortranElement.MainProgram(getCurrentParent()), token), node)); |
| } |
| |
| @Override public void visitASTModuleNode(ASTModuleNode node) |
| { |
| Token token = node.getModuleStmt().getModuleName().getModuleName(); |
| addToModel(node, setPos(configureElement(new FortranElement.Module(getCurrentParent()), token), node)); |
| } |
| |
| @Override public void visitASTSubmoduleNode(ASTSubmoduleNode node) |
| { |
| Token token = node.getSubmoduleStmt().getSubmoduleName().getModuleName(); |
| addToModel(node, setPos(configureElement(new FortranElement.Submodule(getCurrentParent()), token), node)); |
| } |
| |
| @Override public void visitASTFunctionSubprogramNode(ASTFunctionSubprogramNode node) |
| { |
| Token token = node.getFunctionStmt().getFunctionName().getFunctionName(); |
| addToModel(node, setPos(configureElement(new FortranElement.Function(getCurrentParent()), token), node)); |
| } |
| |
| @Override public void visitASTSubroutineSubprogramNode(ASTSubroutineSubprogramNode node) |
| { |
| Token token = node.getSubroutineStmt().getSubroutineName().getSubroutineName(); |
| addToModel(node, setPos(configureElement(new FortranElement.Subroutine(getCurrentParent()), token), node)); |
| } |
| |
| @Override public void visitASTSpecificBindingNode(ASTSpecificBindingNode node) |
| { |
| Token token = node.getBindingName(); |
| addToModel(node, setPos(configureElement(new FortranElement.Subroutine(getCurrentParent()), token), node)); |
| } |
| |
| @Override public void visitASTGenericBindingNode(ASTGenericBindingNode node) |
| { |
| Token token; |
| if (node.getGenericName() != null) |
| { |
| token = node.getGenericName().getGenericName(); |
| } |
| else |
| { |
| ASTGenericSpecNode spec = node.getGenericSpec(); |
| if (spec.isAssignmentOperator()) |
| token = spec.getEqualsToken(); |
| else if (spec.isDefinedOperator()) |
| token = spec.getDefinedOperator().findFirstToken(); |
| else |
| token = spec.findFirstToken(); |
| } |
| addToModel(node, setPos(configureElement(new FortranElement.Subroutine(getCurrentParent()), token), node)); |
| } |
| |
| @Override public void visitASTBlockDataSubprogramNode(ASTBlockDataSubprogramNode node) |
| { |
| Token token = node.getBlockDataStmt().getBlockDataName() == null |
| ? null |
| : node.getBlockDataStmt().getBlockDataName().getBlockDataName(); |
| addToModel(node, setPos(configureElement(new FortranElement.BlockData(getCurrentParent()), token), node)); |
| } |
| |
| @Override public void visitASTDerivedTypeDefNode(ASTDerivedTypeDefNode node) |
| { |
| Token token = node.getDerivedTypeStmt().getTypeName(); |
| addToModel(node, setPos(configureElement(new FortranElement.DerivedType(getCurrentParent()), token), node)); |
| } |
| |
| @Override public void visitASTDataComponentDefStmtNode(ASTDataComponentDefStmtNode node) |
| { |
| for (ASTComponentDeclNode decl : node.getComponentDeclList()) |
| addToModelNoChildren(setPos(configureElement(new FortranElement.Variable(getCurrentParent()), decl.getComponentName().getComponentName()), node)); |
| } |
| |
| @Override public void visitASTExternalStmtNode(ASTExternalStmtNode node) |
| { |
| IASTListNode<ASTExternalNameListNode> list = node.getExternalNameList(); |
| for (int i = 0; i < list.size(); i++) |
| addToModelNoChildren(setPos(configureElement(new FortranElement.Subprogram(getCurrentParent()), list.get(i).getExternalName()), node)); |
| } |
| |
| @Override public void visitASTInterfaceBlockNode(ASTInterfaceBlockNode node) |
| { |
| Token token = node.getInterfaceStmt().getGenericName() == null |
| ? node.getInterfaceStmt().getInterfaceToken() |
| : node.getInterfaceStmt().getGenericName().getGenericName(); |
| addToModel(node, setPos(configureElement(new FortranElement.Subprogram(getCurrentParent()), token), node)); |
| } |
| |
| @Override public void visitASTInterfaceBodyNode(ASTInterfaceBodyNode node) |
| { |
| if (node.getFunctionStmt() != null) |
| { |
| Token token = node.getFunctionStmt().getFunctionName().getFunctionName(); |
| addToModel(node, setPos(configureElement(new FortranElement.Function(getCurrentParent()), token), node)); |
| } |
| else if (node.getSubroutineStmt() != null) |
| { |
| Token token = node.getSubroutineStmt().getSubroutineName().getSubroutineName(); |
| addToModel(node, setPos(configureElement(new FortranElement.Subroutine(getCurrentParent()), token), node)); |
| } |
| } |
| |
| @Override public void visitASTModuleProcedureStmtNode(ASTModuleProcedureStmtNode node) |
| { |
| IASTListNode<ASTProcedureNameListNode> list = node.getProcedureNameList(); |
| for (int i = 0; i < list.size(); i++) |
| addToModelNoChildren(setPos(configureElement(new FortranElement.Subprogram(getCurrentParent()), list.get(i).getProcedureName()), node)); |
| } |
| |
| @Override public void visitASTIntrinsicStmtNode(ASTIntrinsicStmtNode node) |
| { |
| IASTListNode<ASTIntrinsicListNode> list = node.getIntrinsicList(); |
| for (int i = 0; i < list.size(); i++) |
| addToModelNoChildren(setPos(configureElement(new FortranElement.Subprogram(getCurrentParent()), list.get(i).getIntrinsicProcedureName()), node)); |
| } |
| |
| @Override public void visitASTStmtFunctionStmtNode(ASTStmtFunctionStmtNode node) |
| { |
| addToModel(node, setPos(configureElement(new FortranElement.Variable(getCurrentParent()), node.getName().getName()), node)); |
| } |
| |
| private FortranElement configureElement(FortranElement elt, Token nameToken) |
| { |
| modelBuilder.configureElement(elt, nameToken); |
| return elt; |
| } |
| } |