blob: c0da62152de96501cd4f160731fb295fe9aaf0c5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 University of Illinois at Urbana-Champaign and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* UIUC - Initial API and implementation
*******************************************************************************/
package org.eclipse.photran.internal.core.refactoring;
import java.util.List;
import org.eclipse.photran.core.IFortranAST;
import org.eclipse.photran.internal.core.analysis.binding.Definition;
import org.eclipse.photran.internal.core.analysis.binding.ScopingNode;
import org.eclipse.photran.internal.core.analysis.loops.ASTProperLoopConstructNode;
import org.eclipse.photran.internal.core.analysis.loops.ASTVisitorWithLoops;
import org.eclipse.photran.internal.core.analysis.loops.LoopReplacer;
import org.eclipse.photran.internal.core.lexer.FixedFormReplacement;
import org.eclipse.photran.internal.core.lexer.Token;
import org.eclipse.photran.internal.core.lexer.preprocessor.fortran_include.FortranIncludeDirective;
import org.eclipse.photran.internal.core.parser.ASTExecutableProgramNode;
import org.eclipse.photran.internal.core.parser.ASTSubroutineSubprogramNode;
import org.eclipse.photran.internal.core.parser.ASTVisitor;
import org.eclipse.photran.internal.core.parser.IASTNode;
import org.eclipse.photran.internal.core.parser.IExecutableConstruct;
import org.eclipse.photran.internal.core.parser.ISpecificationPartConstruct;
import org.eclipse.photran.internal.core.vpg.PhotranTokenRef;
/**
* This class is for documentation only. It provides several code snippets that illustrate how
* to find things in a Photran AST and how to modify source source code using an AST.
*
* @author Jeff Overbey
*/
// Why is this documentation here rather than the Photran Developer's Guide? Two reasons.
// 1. This Java code actually gets compiled. Examples in a PDF file don't.
// 2. When Eclipse renames classes and methods, it also updates links in JavaDoc. It does not
// refactor examples in a PDF file.
@SuppressWarnings("all")
public class _AST_VPG_HOWTO
{
////////////////////////////////////////////////////////////////////////////////////////////////
// TRAVERSAL & SEARCH
////////////////////////////////////////////////////////////////////////////////////////////////
void iterateThroughAllTokensIn(IASTNode node)
{
node.accept(new ASTVisitor()
{
@Override public void visitToken(Token token)
{
// Do something with token
}
});
}
void iterateThroughAllSubroutinesIn(IASTNode node)
{
node.accept(new ASTVisitor()
{
@Override public void visitASTSubroutineSubprogramNode(ASTSubroutineSubprogramNode node)
{
// Do something with node
}
});
}
void iterateThroughAllDoLoopsIn(IFortranAST ast)
{
// See the Photran Developer's Guide: If you want an AST to have a "proper" structure
// for DO-loops, you must call this method:
LoopReplacer.replaceAllLoopsIn(ast.getRoot());
// ...and then subclass from a different visitor class:
ast.accept(new ASTVisitorWithLoops()
{
@Override public void visitASTProperLoopConstructNode(ASTProperLoopConstructNode node)
{
// Do something with node
}
});
}
void findFirstTokenIn(IASTNode node)
{
Token token = node.findFirstToken(); // Returns null if the node contains no tokens
}
void findRootOfTheAST(IASTNode node)
{
ASTExecutableProgramNode root = node.findNearestAncestor(ASTExecutableProgramNode.class);
}
void findLastSpecificationStmtIn(ASTSubroutineSubprogramNode subroutine)
{
ISpecificationPartConstruct lastStmt =
subroutine.getBody().findLast(ISpecificationPartConstruct.class);
// May be null if there are no specification statements
}
void findFirstExecutableStmtIn(ASTSubroutineSubprogramNode subroutine)
{
IExecutableConstruct firstStmt =
subroutine.getBody().findFirst(IExecutableConstruct.class);
// May be null if there are no executable statements
}
////////////////////////////////////////////////////////////////////////////////////////////////
// WHITETEXT (COMMENTS, WHITESPACE) AND SOURCE CODE
////////////////////////////////////////////////////////////////////////////////////////////////
void printTheSourceCodeFromAnASTNode(IASTNode node)
{
System.out.println(node);
}
void getCommentsAndWhitespacePreceding(IASTNode node)
{
String commentsAndWhitespace = node.findFirstToken().getWhiteBefore();
}
void getCommentsAndWhitespaceAtEndOfFile(IFortranAST ast)
{
String commentsAndWhitespace;
Token lastTokenInFile = ast.getRoot().findLastToken();
if (lastTokenInFile == null)
commentsAndWhitespace = "";
else
commentsAndWhitespace = lastTokenInFile.getWhiteAfter();
}
////////////////////////////////////////////////////////////////////////////////////////////////
// PREPROCESSOR DIRECTIVES
////////////////////////////////////////////////////////////////////////////////////////////////
void dealWithPreprocessing(Token token)
{
if (token.getPreprocessorDirective() == null)
{
// No preprocessing; the token looks exactly the same in the user's source code
}
else if (token.getPreprocessorDirective() instanceof FixedFormReplacement)
{
// Token has spaces in the middle of it which were removed by the fixed form prepass
}
else if (token.getPreprocessorDirective() instanceof FortranIncludeDirective)
{
// Token is in a file included via a Fortran INCLUDE line
}
/*
else if (token.getPreprocessorDirective() instanceof CPreprocessorReplacement)
{
// Token is in a file #included via the C preprocessor,
// or it is the result of a C preprocessor macro expansion,
// or it is contains trigraphs that were replaced by the C preprocessor,
// or something like that.
}
*/
}
////////////////////////////////////////////////////////////////////////////////////////////////
// NAMES, SCOPES, & BINDINGS
////////////////////////////////////////////////////////////////////////////////////////////////
void findScopeOf(IASTNode node)
{
ScopingNode scope = node.findNearestAncestor(ScopingNode.class);
// Note that several different AST nodes are subclasses of ScopingNode --
// ASTExecutableProgramNode (the root of the AST), ASTMainProgramNode,
// ASTFunctionSubprogramNode, etc. -- so any of these may be returned.
}
void findSubroutineContaining(IASTNode node)
{
ASTSubroutineSubprogramNode subroutine =
node.findNearestAncestor(ASTSubroutineSubprogramNode.class);
// Returns null if there is no enclosing subroutine
/* Note that if this is invoked on part of "INTEGER :: I" in
* SUBROUTINE S()
* CONTAINS
* FUNCTION F()
* INTEGER :: I
* END FUNCTION
* END SUBROUTINE
* this will return the ASTSubroutineSubprogramNode for S.
*/
}
void findAllSymbolsDefinedInTheScopeOf(ScopingNode scope)
{
for (Definition symbol : scope.getAllDefinitions())
System.out.println(symbol.getCanonicalizedName());
}
void findAllPublicallyAccessibleSymbolsDefinedIn(ScopingNode scope)
{
for (Definition symbol : scope.getAllPublicDefinitions())
System.out.println(symbol.getCanonicalizedName());
}
void determineWhatSymbolIsDefinedBy(Token identifier)
{
if (identifier.isIdentifier()) // same as identifier.getTerminal() == Terminal.T_IDENT
{
List<Definition> definitions = identifier.resolveBinding();
if (definitions.isEmpty())
{
// The symbol was not declared
}
else if (definitions.size() > 1)
{
// The symbol was declared multiple times, i.e., it is ambiguous
}
else
{
Definition symbol = definitions.get(0);
}
}
}
void findAllPlacesWhereSymbolIsUsed(Definition symbol)
{
for (PhotranTokenRef location : symbol.findAllReferences(true))
{
Token reference = location.findToken();
}
}
void determineIfASymbolHasThePARAMETERAttribute(Definition symbol)
{
if (symbol.isParameter())
System.out.println(true);
}
////////////////////////////////////////////////////////////////////////////////////////////////
// REWRITING
////////////////////////////////////////////////////////////////////////////////////////////////
void makeCopyOf(IASTNode node)
{
IASTNode copy = (IASTNode)node.clone();
}
void changeTheTextOfAToken(Token token)
{
token.setText("whatever");
}
void replacePartOfAnAST()
{
IASTNode node1 = whatever(), node2 = whatever();
node1.replaceWith(node2);
node1.replaceWith("You can also replace a node with a string, like this.");
}
void deletePartOfAnAST(IASTNode node)
{
node.removeFromTree();
}
private IASTNode whatever() { throw new Error(); }
}