blob: 2e3207a5be1450feed0881f86a073245e40e004a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 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.ui.editor_vpg;
import java.io.StringReader;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.photran.core.IFortranAST;
import org.eclipse.photran.internal.core.SyntaxException;
import org.eclipse.photran.internal.core.analysis.binding.Definition;
import org.eclipse.photran.internal.core.lexer.ASTLexerFactory;
import org.eclipse.photran.internal.core.lexer.IAccumulatingLexer;
import org.eclipse.photran.internal.core.lexer.Token;
import org.eclipse.photran.internal.core.lexer.preprocessor.fortran_include.IncludeLoaderCallback;
import org.eclipse.photran.internal.core.parser.ASTExecutableProgramNode;
import org.eclipse.photran.internal.core.parser.Parser;
import org.eclipse.photran.internal.core.properties.SearchPathProperties;
import org.eclipse.photran.internal.core.sourceform.ISourceForm;
import org.eclipse.photran.internal.core.sourceform.SourceForm;
import org.eclipse.photran.internal.core.vpg.PhotranVPG;
import org.eclipse.photran.internal.ui.FortranUIPlugin;
import org.eclipse.photran.internal.ui.editor.FortranEditor;
import org.eclipse.rephraserengine.core.vpg.eclipse.VPGJob;
/**
* Dispatcher for a set of tasks to be run by the Fortran editor when its contents change (and
* after it has had time to parse the modified contents).
*
* @author Jeff Overbey
*/
public class FortranEditorTasks
{
/**
* @return the instance of FortranEditorTasks associated with the given
* editor, creating the instance on-demand if necessary
*/
public static FortranEditorTasks instance(FortranEditor editor)
{
if (editor.reconcilerTasks == null)
editor.reconcilerTasks = new FortranEditorTasks(editor);
return (FortranEditorTasks)editor.reconcilerTasks;
}
private FortranEditorTasks(FortranEditor editor)
{
this.editor = editor;
editor.reconcilerTasks = this;
this.runner = new Runner();
}
//////////////////////////////////////////////////////////////////////////////////////////////
private Parser parser = new Parser();
private FortranEditor editor;
private Runner runner;
/**
* These jobs will be run if the contents of the editor parses successfully. The VPG will probably
* <i>not</i> be up to date, but token positions will correspond to the contents of the editor.
*/
private final Set<IFortranEditorASTTask> astTasks = new HashSet<IFortranEditorASTTask>();
/**
* These jobs will be run when the VPG is more-or-less up-to-date and an AST is available for the
* file in the editor.
*/
private final Set<IFortranEditorVPGTask> vpgTasks = new HashSet<IFortranEditorVPGTask>();
public synchronized void addASTTask(IFortranEditorASTTask task)
{
astTasks.add(task);
}
public synchronized void addVPGTask(IFortranEditorVPGTask task)
{
vpgTasks.add(task);
}
public synchronized void removeASTTask(IFortranEditorASTTask task)
{
astTasks.remove(task);
}
public synchronized void removeVPGTask(IFortranEditorVPGTask task)
{
vpgTasks.remove(task);
}
public Runner getRunner()
{
return runner;
}
public class Runner
{
protected DefinitionMap<Definition> defMap = null;
protected PhotranVPG vpg = PhotranVPG.getInstance();
protected Job dispatchASTTasksJob = null;
protected VPGJob<IFortranAST, Token> updateVPGJob = null;
protected Job dispatchVPGTasksJob = null;
protected IFortranAST vpgAST = null;
public void runTasks()
{
runTasks(true);
}
public void runTasks(boolean runVPGTasks)
{
if (editor == null) return;
String vpgEnabledProperty = new SearchPathProperties().getProperty(editor.getIFile(),
SearchPathProperties.ENABLE_VPG_PROPERTY_NAME);
if (vpgEnabledProperty != null && vpgEnabledProperty.equals("true")) //$NON-NLS-1$
{
runASTTasks();
if (runVPGTasks) runVPGTasks();
}
}
private void runASTTasks()
{
if (dispatchASTTasksJob != null) return; // Already running an update
dispatchASTTasksJob = new DispatchASTTasksJob();
dispatchASTTasksJob.setPriority(Job.DECORATE);
dispatchASTTasksJob.schedule();
}
private void runVPGTasks()
{
if (updateVPGJob != null || dispatchVPGTasksJob != null) return; // Already running an update
//if (vpgAST == null || vpg.db.isOutOfDate(PhotranVPG.getFilenameForIFile(editor.getIFile())))
{
//vpg.queueJobToEnsureVPGIsUpToDate();
vpgAST = null;
updateVPGJob = new UpdateVPGJob();
updateVPGJob.setPriority(Job.DECORATE);
updateVPGJob.schedule();
}
}
private final class DispatchASTTasksJob extends Job
{
private DispatchASTTasksJob()
{
super(Messages.FortranEditorTasks_UpdatingFortranEditorWithNewParseInfo);
}
private ISourceForm determineSourceForm()
{
ISourceForm sourceForm = SourceForm.of(editor.getIFile());
if (editor.getIFile() == null || editor.getIFile().getProject() == null)
return sourceForm.configuredWith(new IncludeLoaderCallback(editor.getIFile().getProject()));
else
return sourceForm;
}
@Override
protected IStatus run(IProgressMonitor monitor)
{
parseThenRunASTTasks();
dispatchASTTasksJob = null;
return Status.OK_STATUS;
}
private void parseThenRunASTTasks()
{
try
{
if (editor.getDocumentProvider() != null)
{
debug("DispatchASTTasksJob#parseThenRunASTTasks():"); //$NON-NLS-1$
String editorContents = editor.getDocumentProvider().getDocument(editor.getEditorInput()).get();
long start = System.currentTimeMillis();
ISourceForm sourceForm = determineSourceForm();
IAccumulatingLexer lexer = new ASTLexerFactory().createLexer(new StringReader(editorContents),
editor.getIFile(),
editor.getIFile().getName(),
sourceForm);
debug(" createLexer:\t" + (System.currentTimeMillis()-start) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$
start = System.currentTimeMillis();
ASTExecutableProgramNode astRootNode = parser.parse(lexer);
debug(" parse:\t" + (System.currentTimeMillis()-start) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$
if (astRootNode == null) return;
HashSet<IFortranEditorASTTask> tasksToRemove = new HashSet<IFortranEditorASTTask>();
synchronized (FortranEditorTasks.instance(editor))
{
start = System.currentTimeMillis();
for (IFortranEditorASTTask task : FortranEditorTasks.instance(editor).astTasks)
{
long start2 = System.currentTimeMillis();
if (!task.handle(astRootNode, lexer.getTokenList(), defMap))
tasksToRemove.add(task);
debug(" Task " + task.getClass().getSimpleName() + ":\t" + (System.currentTimeMillis()-start2) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
debug(" Total Running Tasks:\t" + (System.currentTimeMillis()-start) + " ms"); //$NON-NLS-1$ //$NON-NLS-2$
}
FortranEditorTasks.instance(editor).astTasks.removeAll(tasksToRemove);
}
}
catch (SyntaxException e) { /* Ignore syntax errors */ }
catch (Throwable e) { FortranUIPlugin.log(Messages.FortranEditorTasks_ErrorRunningASTTasks, e); }
}
private void debug(String string)
{
PhotranVPG.getInstance().debug(string, null);
}
}
private final class UpdateVPGJob extends VPGJob<IFortranAST, Token>
{
private UpdateVPGJob()
{
super(Messages.FortranEditorTasks_UpdatingFortranEditorWithNewAnalysisInfo);
}
@Override
public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException
{
vpgAST = vpg.acquireTransientAST(PhotranVPG.getFilenameForIFile(editor.getIFile()));
updateVPGJob = null;
//scheduleVPGTaskDispatchJob();
if (vpgAST != null)
{
// Copy list of tasks so we can iterate over it without a
// ConcurrentModificationException and without having to
// synchronize for the entire time we're running the tasks,
// since this will block the UI thread if AST tasks also
// want to run
Set<IFortranEditorVPGTask> vpgTasks;
synchronized (FortranEditorTasks.instance(editor))
{
vpgTasks = new HashSet<IFortranEditorVPGTask>(FortranEditorTasks.instance(editor).vpgTasks);
}
defMap = createDefMap();
for (IFortranEditorVPGTask task : vpgTasks)
task.handle(editor.getIFile(), vpgAST, defMap);
}
return Status.OK_STATUS;
}
private DefinitionMap<Definition> createDefMap()
{
return new DefinitionMap<Definition>(vpgAST)
{
@Override protected Definition map(String qualifiedName, Definition def)
{
return def;
}
};
}
}
}
}