/*
* This file is part of the X10 project (http://x10-lang.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* This file was originally derived from the Polyglot extensible compiler framework.
*
* (C) Copyright 2000-2007 Polyglot project group, Cornell University
* (C) Copyright IBM Corporation 2007-2012.
*/
package polyglot.frontend;
import java.util.*;
import polyglot.frontend.Goal.Status;
import polyglot.main.Reporter;
import polyglot.types.LazyRef_c;
import polyglot.util.StringUtil;
public abstract class AbstractGoal_c extends LazyRef_c<Goal.Status> implements Goal {
private static final long serialVersionUID = 39827248332800427L;
String name;
private List<Goal> prereqs;
protected Scheduler scheduler = null;
private List<GoalListener> listeners;
public final Goal intern(Scheduler scheduler) {
this.scheduler = scheduler;
return scheduler.intern(this);
}
protected AbstractGoal_c() {
this(null);
}
protected AbstractGoal_c(String name) {
super(Status.NEW);
this.name = name==null ? StringUtil.getShortNameComponent(getClass().getName().replace('$', '.')) : name;
setResolver(this);
}
public boolean addListener(GoalListener listener) {
Goal g = this;
if (scheduler != null)
g = this.intern(scheduler);
if (g != this)
return g.addListener(listener);
boolean adding = true;
if (listeners == null) {
listeners = new ArrayList<GoalListener>();
} else {
for (GoalListener l : listeners) {
if (l == listener) {
adding = false;
break;
}
}
}
if (adding)
listeners.add(listener);
return adding;
}
public void run() {
AbstractGoal_c goal = this;
Reporter reporter = scheduler.extensionInfo().getOptions().reporter;
if (reporter.should_report(reporter.frontend, 2))
reporter.report(2, "Running to goal " + goal);
LinkedList<Goal> worklist = new LinkedList<Goal>(prereqs());
Set<Goal> prereqs = new LinkedHashSet<Goal>();
prereqs.addAll(worklist);
while (! worklist.isEmpty()) {
Goal g = worklist.removeFirst();
if (g.getCached() == Goal.Status.SUCCESS)
continue;
if (reporter.should_report(reporter.frontend, 4))
reporter.report(4, "running prereq: " + g + "->" + goal);
Status s = g.get();
// Make sure any new prereqs added during the recursion are in the queue.
for (Goal g2 : prereqs()) {
if (! prereqs.contains(g2)) {
prereqs.add(g2);
worklist.add(g2);
}
}
switch (s) {
case NEW:
case FAIL:
case RUNNING:
case RUNNING_RECURSIVE:
case RUNNING_WILL_FAIL:
case UNREACHABLE:
update(Status.UNREACHABLE);
continue;
case SUCCESS:
break;
}
}
Status oldStatus = getCached();
switch (oldStatus) {
case RUNNING:
case RUNNING_RECURSIVE:
updateCache(Status.RUNNING_RECURSIVE);
break;
case NEW:
updateCache(Status.RUNNING);
break;
case RUNNING_WILL_FAIL:
default:
return;
}
boolean recursive = oldStatus == Status.RUNNING_RECURSIVE;
if (reporter.should_report(reporter.frontend, 4))
reporter.report(4, "running goal " + goal);
if (reporter.should_report(reporter.frontend, 5)) {
if (scheduler.currentGoal() != null) {
reporter.report(5, "CURRENT = " + scheduler.currentGoal());
reporter.report(5, "SPAWN = " + goal);
}
}
boolean result = false;
try {
if (listeners != null) {
for (GoalListener l : listeners) {
l.taskStarted(this);
}
}
result = scheduler.runPass(this);
if (state() == Goal.Status.RUNNING_WILL_FAIL)
result = false;
}
catch (CyclicDependencyException e) {
}
if (result) {
switch (oldStatus) {
case RUNNING:
case RUNNING_RECURSIVE:
update(oldStatus);
break;
case NEW:
update(Status.SUCCESS);
break;
default:
break;
}
}
else {
switch (oldStatus) {
case RUNNING:
case RUNNING_RECURSIVE:
update(Status.RUNNING_WILL_FAIL);
break;
case NEW:
update(Status.FAIL);
break;
default:
break;
}
}
}
public abstract boolean runTask();
public List<Goal> prereqs() {
if (prereqs == null) {
return Collections.emptyList();
}
else {
return Collections.unmodifiableList(prereqs);
}
}
public void addPrereq(final Goal goal) {
if (prereqs == null) {
prereqs = new ArrayList<Goal>();
}
prereqs.add(goal);
}
public boolean hasBeenReached() {
return getCached() == Status.SUCCESS;
}
public boolean isReachable() {
Status state = getCached();
switch (state) {
case NEW:
case RUNNING:
case RUNNING_RECURSIVE:
case SUCCESS:
return true;
case RUNNING_WILL_FAIL:
case FAIL:
case UNREACHABLE:
return false;
default:
return false;
}
}
public String name() {
return name;
}
public Status state() {
return getCached();
}
public int hashCode() {
return name().hashCode();
}
public boolean equals(Object o) {
if (o instanceof Goal) {
Goal g = (Goal) o;
return name().equals(g.name());
}
return false;
}
public boolean isRunning() {
switch (state()) {
case RUNNING:
case RUNNING_RECURSIVE:
case RUNNING_WILL_FAIL:
return true;
default:
return false;
}
}
public void fail() {
switch (state()) {
case SUCCESS:
assert false;
break;
case RUNNING:
case RUNNING_RECURSIVE:
update(Goal.Status.RUNNING_WILL_FAIL);
break;
case NEW:
update(Goal.Status.UNREACHABLE);
break;
case RUNNING_WILL_FAIL:
case FAIL:
case UNREACHABLE:
break;
}
}
protected String stateString() {
Status state = state();
switch (state) {
case NEW:
return "new";
case RUNNING:
return "running";
case RUNNING_RECURSIVE:
return "running-recursive";
case RUNNING_WILL_FAIL:
return "running-will-fail";
case SUCCESS:
return "success";
case FAIL:
return "failed";
case UNREACHABLE:
return "unreachable";
}
return "unknown-goal-state";
}
public String toString() {
return name() + " (" + stateString() + ")";
}
}