Commit 140e6118 authored by Administrator's avatar Administrator
Browse files

Initiales Project Release - Grundlegende Einbettung des Compilers

parents
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry exported="true" kind="lib" path="java-cup-11b-runtime.jar"/>
<classpathentry kind="lib" path="/MiniJava/dist/Compiler.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>MJPlugin</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: MJPlugin
Bundle-SymbolicName: MJPlugin;singleton:=true
Bundle-Version: 1.0
Bundle-Activator: mjplugin.Activator
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.ui.editors;bundle-version="3.8.200",
org.eclipse.core.resources
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Import-Package: org.eclipse.jface.text,
org.eclipse.jface.text.source,
org.eclipse.ui.editors.text
source.. = src/
output.. = bin/
bin.includes = plugin.xml,\
META-INF/,\
.
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
<extension
point="org.eclipse.ui.editors">
<editor
class="mjplugin.editors.MJEditor"
default="false"
extensions="mj"
id="MJPlugin.MJEditor"
name="MJ Editor">
</editor>
</extension>
</plugin>
package mjplugin;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
/**
* The activator class controls the plug-in life cycle
*/
public class Activator extends AbstractUIPlugin {
// The plug-in ID
public static final String PLUGIN_ID = "MJPlugin"; //$NON-NLS-1$
// The shared instance
private static Activator plugin;
/**
* The constructor
*/
public Activator() {
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}
/**
* Returns the shared instance
*
* @return the shared instance
*/
public static Activator getDefault() {
return plugin;
}
/**
* Returns an image descriptor for the image file at the given
* plug-in relative path
*
* @param path the path
* @return the image descriptor
*/
public static ImageDescriptor getImageDescriptor(String path) {
return imageDescriptorFromPlugin(PLUGIN_ID, path);
}
}
package mjplugin.ast;
import minijava.Program;
public class MiniJavaAST {
public Program program;
public MiniJavaAST(Program program) {
this.program = program;
}
}
package mjplugin.controller;
import java.util.List;
import mjplugin.editors.MJEditor;
import mjplugin.model.Model;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.ui.progress.UIJob;
class CallbackJob extends UIJob {
private MJEditor editor = null;
private List<JobStatus>jobStatusList;
public CallbackJob(MJEditor editor, List<JobStatus>jobStatusList) {
super("" + editor.hashCode());
this.editor = editor;
this.jobStatusList = jobStatusList;
}
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
for(JobStatus status:jobStatusList)
Controller.getInstance(editor).notifyObserversOfJobStatus(status);
if (editor == null || editor.hasBeenDisposed())
return Status.CANCEL_STATUS;
Controller.getInstance(editor).notifyChangeJobFinished();
return Status.OK_STATUS;
}
}
\ No newline at end of file
package mjplugin.controller;
import java.util.Collections;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.WeakHashMap;
import mjplugin.editors.MJEditor;
import mjplugin.editors.RevisionManager;
import mjplugin.model.Model;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
public class Controller {
public static enum JobsToDo {
doNothing, parseCode
};
private static WeakHashMap<MJEditor, Controller> instances = new WeakHashMap<MJEditor, Controller>();
public static Controller getInstance(MJEditor editor) {
if (editor == null)
throw new RuntimeException("editor must not be null.");
Controller instance = instances.get(editor);
if (instance != null)
return instance;
else {
instances.put(editor, new Controller(editor));
return instances.get(editor);
}
}
private MJEditor editor;
private List<DocumentEvent> documentEvents;
private DocumentDidChangeJob job = null;
private Controller(MJEditor editor) {
this.editor = editor;
job = new DocumentDidChangeJob(editor);
job.setSystem(true);
documentEvents = new LinkedList<DocumentEvent>();
}
private Set<IRegisterForControllerChanges> controllerObservers = Collections
.newSetFromMap(new WeakHashMap<IRegisterForControllerChanges, Boolean>());
private final EnumSet<JobsToDo> jobElements = EnumSet
.noneOf(JobsToDo.class);
/**
* Request a run of all necessary jobs, this method returns true if the jobs
* will run and false if no job is required because the actual model
* revision has the same number as the document revision
*
* @return if the job will ever run
*/
public boolean requestJobRun() {
IDocument document = editor.getDocument();
EnumSet<JobsToDo> observedJobs = EnumSet.noneOf(JobsToDo.class);
synchronized (controllerObservers) {
for (IRegisterForControllerChanges observer : controllerObservers)
observedJobs.addAll(observer.getRequiredJobs());
}
for (JobsToDo job : observedJobs) {
switch (job) {
case parseCode:
long modelAstRev = Model.getInstanceForDocument(document)
.getAstModelRevisionNumber();
if (modelAstRev != RevisionManager.get(document))
addJobToDo(job);
break;
default:
break;
}
}
synchronized (jobElements) {
if (jobElements.isEmpty()) {
return false;
}
}
runJobs(document);
return true;
}
private static final int SET_CHANGED_AFTER_SECONDS = 1;
private void runJobs(IDocument document) {
if (job.getState() == Job.NONE
|| (!job.running() && job.getState() == Job.SLEEPING)) {
job.cancel();
job.revNumber = RevisionManager.increment(document);
job.schedule(SET_CHANGED_AFTER_SECONDS * 1000);
} else {
RevisionManager.increment(document);
changeJobReRunRequested = System.currentTimeMillis();
}
}
private void addJobToDo(JobsToDo job) {
synchronized (jobElements) {
jobElements.add(job);
}
}
// if the changeJob takes some time, it's good to know if it has to be
// reexecuted after it finishes
private long changeJobReRunRequested = 0;
private final Object lock = new Object();
/*
* notify callback, that the changeJob did finish
*/
public void notifyChangeJobFinished() {
synchronized (lock) {
if (changeJobReRunRequested > 0) {
changeJobReRunRequested = 0;
// TODO: why is this only multiplied by 100 here, but 1000 above
// ???
long remainderOfDelay = (SET_CHANGED_AFTER_SECONDS * 100)
- (System.currentTimeMillis() - changeJobReRunRequested);
job.revNumber = RevisionManager.get(editor.getDocument());
job.schedule((remainderOfDelay >= 0) ? remainderOfDelay : 0);
}
}
}
public void notifyObserversOfJobStatus(JobStatus status) {
synchronized (controllerObservers) {
for (IRegisterForControllerChanges observer : controllerObservers)
observer.jobStatusChanged(status);
}
}
public EnumSet<JobsToDo> popJobsToDo() {
synchronized (jobElements) {
final EnumSet<JobsToDo> popJobs = EnumSet.noneOf(JobsToDo.class);
popJobs.addAll(jobElements);
jobElements.clear();
return popJobs;
}
}
public List<DocumentEvent> popAllDocumentEvents() {
synchronized (documentEvents) {
List<DocumentEvent> popList = this.documentEvents;
this.documentEvents = new LinkedList<DocumentEvent>();
return popList;
}
}
}
package mjplugin.controller;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Date;
import java.util.EnumSet;
import java.util.List;
import miniparser.InMemoryParser;
import mjplugin.ast.MiniJavaAST;
import mjplugin.controller.Controller.JobsToDo;
import mjplugin.editors.MJEditor;
import org.eclipse.core.resources.IFile;
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.jface.text.DocumentEvent;
public class DocumentDidChangeJob extends Job {
boolean currentlyRunning = false;
MJEditor editor = null;
List<DocumentEvent> documentEvents;
EnumSet<JobsToDo> jobs;
String codeText;
private MiniJavaAST result;
private List<JobStatus> jobStatusList;
public long revNumber;
public DocumentDidChangeJob(MJEditor editor) {
super("" + editor.hashCode());
this.editor = editor;
this.jobStatusList = new ArrayList<JobStatus>();
}
public boolean running() {
return currentlyRunning;
}
@Override
protected IStatus run(IProgressMonitor monitor) {
currentlyRunning = true;
jobStatusList.clear();
SetupJob setup = new SetupJob(editor, revNumber, this);
setup.setSystem(true);
setup.schedule();
try {
setup.join();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
if (setup.getResult() == Status.CANCEL_STATUS)
return Status.CANCEL_STATUS;
if (editor == null || editor.getDocument() == null) {
System.err.println("DocumentDidChangeJob.run(): editor or document NULL.");
return Status.CANCEL_STATUS;
}
Date parserDate = null;
Date lalrDate = null;
boolean hasParserErrors = false;
InMemoryParser parser = null;
//Parser parser = null;
if (jobs.contains(JobsToDo.parseCode)) {
InputStream in = new ByteArrayInputStream(codeText.getBytes());
parser = new InMemoryParser(in);
result = null;
try {
parserDate = new Date();
result = new MiniJavaAST(parser.parse());
} catch (Exception e1) {
e1.printStackTrace();
}
if (result != null) {
//if (parser.hasParseErrors())
// hasParserErrors = true;
jobStatusList.add(new JobStatus(JobsToDo.parseCode, false));
ParserResultJob resultModelJob = new ParserResultJob(editor,
result, revNumber);
resultModelJob.setSystem(true);
resultModelJob.schedule();
try {
resultModelJob.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
hasParserErrors = true;
jobStatusList.add(new JobStatus(JobsToDo.parseCode, true));
}
}
documentEvents.clear();
jobs.clear();
currentlyRunning = false;
CallbackJob cb = new CallbackJob(editor, jobStatusList);
cb.setSystem(true);
cb.schedule();
return Status.OK_STATUS;
}
}
package mjplugin.controller;
import java.util.EnumSet;
import mjplugin.controller.Controller.JobsToDo;
public interface IRegisterForControllerChanges {
/**
* Registered controller observers are queried before the job pipeline
* is run and can indicate which jobs they required to be executed.
* Observers who do not depend on the data but simply perform e.g. logging
* activities should return an empty set.
*/
EnumSet<JobsToDo> getRequiredJobs();
void jobStatusChanged(JobStatus status);
}
package mjplugin.controller;
import mjplugin.controller.Controller.JobsToDo;
public class JobStatus {
private boolean failed;
private String message;
private JobsToDo affectedJob;
public JobStatus(JobsToDo affectedJob, boolean failed) {
this(affectedJob, failed, null);
}
public JobStatus(JobsToDo affectedJob, boolean failed, String message) {
this.affectedJob = affectedJob;
this.failed = failed;
this.message = message;
}
public boolean hasFailed() {
return failed;
}
public String getMessage() {
return message;
}
public JobStatus(boolean failed) {
this.failed = failed;
}
public JobsToDo getAffectedJob() {
return affectedJob;
}
public void setAffectedJob(JobsToDo affectedJob) {
this.affectedJob = affectedJob;
}
}
package mjplugin.controller;
import mjplugin.ast.MiniJavaAST;
import mjplugin.editors.MJEditor;
import mjplugin.model.Model;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.text.IDocument;
import org.eclipse.ui.progress.UIJob;
class ParserResultJob extends UIJob {
private MJEditor editor;
private MiniJavaAST parserResult;
private long parserModelRevisionNumber;
public ParserResultJob(MJEditor editor, MiniJavaAST result, long revisionNumber) {
super("Parser Result UI Job");
this.editor = editor;
this.parserResult = result;
this.parserModelRevisionNumber = revisionNumber;
}
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
if (editor == null || editor.hasBeenDisposed())
return Status.CANCEL_STATUS;
IDocument document = editor.getDocument();
if (document != null) {
Model model = Model.getInstanceForDocument(document);
model.setASTModel(this.parserResult, parserModelRevisionNumber);
return Status.OK_STATUS;
}
return Status.CANCEL_STATUS;
}
}
package mjplugin.controller;
import mjplugin.editors.MJEditor;
import mjplugin.editors.RevisionManager;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.text.IDocument;
import org.eclipse.ui.progress.UIJob;
class SetupJob extends UIJob {
private DocumentDidChangeJob ddcJob;
private MJEditor editor;
private long revision;
public SetupJob(MJEditor editor, long revision,
DocumentDidChangeJob documentDidChangeJob) {
super("Parser Setup Job");
this.editor = editor;
this.ddcJob = documentDidChangeJob;
this.revision = revision;
}
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
Controller controller = Controller.getInstance(editor);