blob: 378af8bc6f5d879646e00d77de1593c5265949e2 [file] [log] [blame]
package org.eclipse.photran.internal.core.model;
import java.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.IContributedModelBuilder;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.internal.core.model.Parent;
import org.eclipse.cdt.internal.core.model.TranslationUnit;
import org.eclipse.core.resources.IFile;
import org.eclipse.photran.core.IFortranAST;
import org.eclipse.photran.internal.core.FortranAST;
import org.eclipse.photran.internal.core.analysis.loops.LoopReplacer;
import org.eclipse.photran.internal.core.lexer.IAccumulatingLexer;
import org.eclipse.photran.internal.core.lexer.LexerFactory;
import org.eclipse.photran.internal.core.lexer.SourceForm;
import org.eclipse.photran.internal.core.lexer.preprocessor.fortran_include.IncludeLoaderCallback;
import org.eclipse.photran.internal.core.parser.Parser;
import org.eclipse.photran.internal.core.preferences.FortranPreferences;
/**
* This is a Fortran model builder which uses the Fortran parser to construct the model.
* See {@link IFortranModelBuilder}.
* <p>
* This is Photran's default model builder, assuming the VPG plug-ins are available, so the model
* you see in the Outline view is probably constructed by this model builder. There is also
* {@link org.eclipse.photran.internal.core.model.SimpleFortranModelBuilder}, a simpler model
* builder which is based solely on the Fortran lexer.
* <p>
* Editors can force the model builder to use fixed or free format for a given file by calling
* {@link #setIsFixedForm(boolean)}. Otherwise, the format is determined by content type (i.e., by
* the filename extension and the user's workspace preferences).
* <p>
* Internally, this model builder uses a {@link FortranModelBuildingVisitor} to construct the model
* by visiting the Fortran AST.
*
* @author Jeff Ooverbey
*
* @see IFortranModelBuilder
* @see IContributedModelBuilder
*/
@SuppressWarnings("restriction")
public class FortranModelBuilder implements IFortranModelBuilder
{
private TranslationUnit translationUnit;
private Map<ICElement, Object /*CElementInfo*/> newElements;
private boolean isFixedForm;
public void setTranslationUnit(ITranslationUnit tu)
{
if (!(tu instanceof TranslationUnit)) throw new Error("Unexpected subclass of ITranslationUnit");
this.translationUnit = (TranslationUnit)tu;
}
public void setIsFixedForm(boolean isFixedForm)
{
this.isFixedForm = isFixedForm;
}
public void parse(boolean quickParseMode) throws Exception
{
this.newElements = new HashMap<ICElement, Object /*CElementInfo*/>();
boolean wasSuccessful = true;
IAccumulatingLexer lexer = null;
try
{
IFile file = translationUnit.getFile();
lexer = LexerFactory.createLexer(
new ByteArrayInputStream(translationUnit.getBuffer().getContents().getBytes()),
file,
determineFilename(file),
determineSourceForm(file),
true /*false*/);
// There may be more than one FortranModelBuilder running at once, so, unfortunately, we have to
// create a new parser each time
IFortranAST ast = new FortranAST(file, new Parser().parse(lexer), lexer.getTokenList());
createSourceFormNode();
if (isParseTreeModelEnabled())
{
LoopReplacer.replaceAllLoopsIn(ast.getRoot());
ast.accept(new FortranParseTreeModelBuildingVisitor(translationUnit, this));
}
else
{
ast.accept(new FortranModelBuildingVisitor(translationUnit, this));
}
//FortranElement note = new FortranElement.UnknownNode(translationUnit, isFixedForm ? "<Fixed Form Source>" : "<Free Form Source>");
//this.addF90Element(note);
/* For whatever reason, we have to only set the *parent* while we
* parse, then go back through (now) and traverse the model in
* preorder, executing addChild(). This doesn't make any sense,
* but the "obvious" way of doing it all while parsing (in
* BuildModelParserAction.java) doesn't work.
*/
//newElements.putAll(newElts);
//this.addF90Elements(newElements);
}
catch (Exception e)
{
FortranElement elt = createParseFailureNode(translationUnit, e.getMessage());
if (lexer != null)
{
int offset = lexer.getLastTokenFileOffset();
int length = lexer.getLastTokenLength();
int line = lexer.getLastTokenLine();
if (offset >= 0 && length > 0)
{
elt.setIdPos(offset, length);
elt.setPos(offset, length);
if (line > 0) elt.setLines(line, line);
}
}
wasSuccessful = false;
}
// From CDT: important to know if the unit has parse errors or not
setIsStructureKnown(wasSuccessful);
}
private String determineFilename(IFile file)
{
if (file == null)
return "";
else if (isLocal(file)) // C preprocessor requires absolute path
return file.getLocation().toFile().getAbsolutePath();
else
return file.getName();
}
private SourceForm determineSourceForm(IFile file)
{
if (isFixedForm)
{
return SourceForm.FIXED_FORM;
}
else
{
if (isLocal(file) && file.getProject() != null)
return SourceForm.preprocessedFreeForm(new IncludeLoaderCallback(file.getProject()));
else
return SourceForm.UNPREPROCESSED_FREE_FORM;
}
}
private boolean isLocal(IFile file)
{
return file != null && file.getLocation() != null;
}
public void setIsStructureKnown(boolean isStructureKnown)
{
translationUnit.setIsStructureKnown(isStructureKnown);
}
private boolean isParseTreeModelEnabled()
{
return FortranPreferences.SHOW_PARSE_TREE.getValue();
}
// --NODE CREATION METHODS-------------------------------------------
private FortranElement createSourceFormNode() throws CModelException
{
String sourceForm = isFixedForm ? "<Fixed Form Source>" : "<Free Form Source>";
FortranElement element = new FortranElement.UnknownNode(translationUnit, sourceForm);
translationUnit.addChild(element);
this.newElements.put(element, element.getElementInfo());
return element;
}
// private FortranElement createParseFailureNode(Parent parent, Token errorToken)
// throws CModelException
// {
//
// StringBuffer errorMessage = new StringBuffer();
// errorMessage.append("Error: Unexpected ");
// errorMessage.append(errorToken.getTerminal().getDescription());
// errorMessage.append(" \"");
// errorMessage.append(errorToken.getText());
// errorMessage.append("\"");
// FortranElement element = new FortranElement.ErrorNode(parent, errorMessage.toString());
// element.setIdPos(errorToken.getOffset(), errorToken.getLength());
// element.setPos(errorToken.getOffset(), errorToken.getLength());
// element.setLines(errorToken.getStartLine(), errorToken.getEndLine());
//
// parent.addChild(element);
// this.newElements.put(element, element.getElementInfo());
// return element;
//
// }
private FortranElement createParseFailureNode(Parent parent, String errorMessage)
throws CModelException
{
FortranElement element = new FortranElement.ErrorNode(parent, errorMessage);
parent.addChild(element);
this.newElements.put(element, element.getElementInfo());
return element;
}
// private FortranElement createSemanticFailureNode(Parent parent, SemanticError e)
// throws CModelException
// {
//
// StringBuffer errorMessage = new StringBuffer();
// errorMessage.append(e.getMessage());
// Token errorToken = e.getErrorToken();
// if (errorToken == null) errorToken = new Token();
// FortranElement element = new FortranElement.ErrorNode(parent, errorMessage.toString());
// element.setIdPos(errorToken.getOffset(), errorToken.getLength());
// element.setPos(errorToken.getOffset(), errorToken.getLength());
// element.setLines(errorToken.getStartLine(), errorToken.getEndLine());
//
// parent.addChild(element);
// this.newElements.put(element, element.getElementInfo());
// return element;
//
// }
/**
* Callback method invoked by the {@link FortranModelBuildingVisitor} to add nodes to the model.
*
* @param element
* @return element
*
* @throws CModelException
*/
public FortranElement addF90Element(FortranElement element) throws CModelException
{
if (element.getParent() == null) element.setParent(translationUnit);
ICElement parent = element.getParent();
if (parent instanceof Parent) ((Parent)parent).addChild(element);
this.newElements.put(element, element.getElementInfo());
return element;
}
}