/*
* 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
*
* (C) Copyright IBM Corporation 2006-2010.
*/
package x10.dom;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import polyglot.ast.Node;
import polyglot.ast.SourceFile;
import x10.Configuration;
import x10.ExtensionInfo;
import x10.ExtensionInfo.X10Scheduler;
import x10.ast.X10NodeFactory;
import x10.plugin.CompilerPlugin;
import x10.types.X10TypeSystem;
import polyglot.frontend.AbstractPass;
import polyglot.frontend.Job;
import polyglot.frontend.Pass;
import polyglot.frontend.Scheduler;
import polyglot.frontend.goals.AbstractGoal;
import polyglot.frontend.goals.Goal;
import polyglot.main.Report;
import polyglot.util.ErrorInfo;
import polyglot.util.ErrorQueue;
import polyglot.util.QuotedStringTokenizer;
import polyglot.visit.NodeVisitor;
/**
* This plugin exports the AST as an XML file, forks an external tool to process
* the file, waits until the tool finishes, then reads back in the XML,
* replacing the AST.
*/
public class ExternalizerPlugin implements CompilerPlugin {
public ExternalizerPlugin() {
super();
}
protected static class ExternalizerPass extends AbstractPass {
private final polyglot.frontend.ExtensionInfo info;
protected ExternalizerPass(Goal goal, polyglot.frontend.ExtensionInfo info) {
super(goal);
this.info = info;
}
public boolean run() {
Job job = this.goal().job();
X10TypeSystem ts = (X10TypeSystem) info.typeSystem();
X10NodeFactory nf = (X10NodeFactory) info.nodeFactory();
String xmlFile = getXMLFileName(info, job);
ErrorQueue eq = job.compiler().errorQueue();
String xmlProcessor = Configuration.XML_PROCESSOR;
boolean exportXML = Configuration.EXTERNALIZE_ASTS;
boolean importXML = false;
if (xmlProcessor != null && ! xmlProcessor.equals("")) {
exportXML = true;
importXML = true;
}
if (Report.should_report("xml", 1)) {
exportXML = true;
importXML = true;
}
X10Dom dom = new X10Dom(ts, nf);
if (exportXML) {
DomGenerator gen = new DomGenerator();
org.w3c.dom.Element e = gen.gen(dom, job.ast());
try {
XMLWriter w = new XMLWriter(xmlFile);
w.writeElement(e);
w.close();
}
catch (IOException ex) {
eq.enqueue(ErrorInfo.IO_ERROR, ex.getMessage());
return false;
}
}
if (xmlProcessor != null && ! xmlProcessor.equals("")) {
if (! processXMLFile(xmlFile, xmlProcessor, eq)) {
return false;
}
}
if (importXML) {
org.w3c.dom.Element e;
try {
XMLReader r = new XMLReader(xmlFile);
e = r.readElement();
r.close();
}
catch (IOException ex) {
eq.enqueue(ErrorInfo.IO_ERROR, ex.getMessage());
return false;
}
DomReader ungen = new DomReader(ts, nf, job.source());
Node n = ungen.fromXML(dom, e);
job.ast(n);
}
return true;
}
private boolean processXMLFile(String xmlFile, String xmlProcessor, ErrorQueue eq) {
boolean okay = true;
Runtime runtime = Runtime.getRuntime();
QuotedStringTokenizer st = new QuotedStringTokenizer(xmlProcessor);
int pc_size = st.countTokens();
String[] cmd = new String[pc_size+1];
int j = 0;
for (int i = 0; i < pc_size; i++) {
cmd[j++] = st.nextToken();
}
cmd[j++] = xmlFile;
if (Report.should_report(Report.verbose, 1)) {
StringBuffer cmdStr = new StringBuffer();
for (int i = 0; i < cmd.length; i++)
cmdStr.append(cmd[i]+" ");
Report.report(1, "Executing XML processor " + cmdStr);
}
try {
Process proc = runtime.exec(cmd);
InputStreamReader err = new InputStreamReader(proc.getErrorStream());
try {
char[] c = new char[72];
int len;
StringBuffer sb = new StringBuffer();
while((len = err.read(c)) > 0) {
sb.append(String.valueOf(c, 0, len));
}
if (sb.length() != 0) {
eq.enqueue(ErrorInfo.POST_COMPILER_ERROR, sb.toString());
}
}
finally {
err.close();
}
proc.waitFor();
if (proc.exitValue() > 0) {
eq.enqueue(ErrorInfo.POST_COMPILER_ERROR,
"Non-zero return code: " + proc.exitValue());
okay = false;
}
}
catch(Exception ex) {
eq.enqueue(ErrorInfo.POST_COMPILER_ERROR, ex.getMessage());
okay = false;
}
return okay;
}
protected String getXMLFileName(final polyglot.frontend.ExtensionInfo extInfo, Job job) {
final String[] packageName = new String[1];
job.ast().visit(new NodeVisitor() {
public Node override(Node n) {
if (n instanceof SourceFile) {
SourceFile sf = (SourceFile) n;
if (sf.package_() != null) {
packageName[0] = sf.package_().package_().fullName();
}
return n;
}
return null;
}
});
File f = extInfo.targetFactory().outputFile(packageName[0], job.source());
String xmlFile = f.getPath();
int index = f.getPath().lastIndexOf(".java");
if (index >= 0) {
xmlFile = f.getPath().substring(0, index) + ".x10ml";
}
else {
xmlFile = f.getPath() + ".x10ml";
}
return xmlFile;
}
}
public static class ExternalizerPluginGoal extends AbstractGoal {
public static Goal create(Scheduler scheduler, Job job) {
return scheduler.internGoal(new ExternalizerPluginGoal(job));
}
private ExternalizerPluginGoal(Job job) {
super(job);
}
public Collection prerequisiteGoals(Scheduler scheduler) {
X10Scheduler x10Sched = (X10Scheduler) scheduler;
List<Goal> l = new ArrayList<Goal>();
l.add(x10Sched.TypeChecked(job));
l.add(x10Sched.ConstantsChecked(job));
l.add(x10Sched.PropagateAnnotations(job));
l.addAll(super.prerequisiteGoals(scheduler));
return l;
}
@Override
public Pass createPass(final polyglot.frontend.ExtensionInfo extInfo) {
return new ExternalizerPass(this, extInfo);
}
}
public Goal register(ExtensionInfo extInfo, Job job) {
Goal g = ExternalizerPluginGoal.create(extInfo.scheduler(), job);
X10Scheduler x10Sched = (X10Scheduler) extInfo.scheduler();
x10Sched.addDependencyAndEnqueue(x10Sched.X10Boxed(job), g, true);
return g;
}
}