00001
00005 package edu.mit.csail.sdg.squander.spec;
00006
00007 import java.io.IOException;
00008 import java.lang.reflect.Field;
00009 import java.lang.reflect.Method;
00010 import java.net.URL;
00011 import java.util.LinkedList;
00012 import java.util.List;
00013
00014 import org.antlr.runtime.ANTLRInputStream;
00015 import org.antlr.runtime.CommonTokenStream;
00016 import org.antlr.runtime.RecognitionException;
00017 import org.antlr.runtime.tree.TreeAdaptor;
00018
00019 import edu.mit.csail.sdg.squander.spec.Source.Rule;
00020 import edu.mit.csail.sdg.squander.specfile.parser.SpecFileLexer;
00021 import edu.mit.csail.sdg.squander.specfile.parser.SpecFileParser;
00022 import edu.mit.csail.sdg.squander.specfile.parser.SpecFileParserException;
00023 import edu.mit.csail.sdg.squander.specfile.parser.SpecFileVisitor;
00024 import edu.mit.csail.sdg.squander.specfile.parser.SpecFileParser.Node;
00025
00026
00027 public class SpecFileSpecProvider implements ISpecProvider {
00028
00029 class MyVisitor extends SpecFileVisitor<List<Source>> {
00030
00031 private final JType.Unary jtype;
00032 private final NameSpace ns;
00033
00034 public MyVisitor(JType.Unary jtype) {
00035 this.jtype = jtype;
00036 this.ns = NameSpace.forClass(jtype);
00037 }
00038
00039 @Override
00040 protected List<Source> visitInvariant(Node n) {
00041 List<Source> l = new LinkedList<Source>();
00042 for (int i = 0; i < n.getChildCount(); i++)
00043 l.add(new Source(trimQuotes(asText(n.getChild(i))), ns, Rule.CLAUSE));
00044 return l;
00045 }
00046
00047 @Override
00048 protected List<Source> visitSpecField(Node n) {
00049 List<Source> l = new LinkedList<Source>();
00050 for (int i = 0; i < n.getChildCount(); i++)
00051 l.add(new Source(trimQuotes(asText(n.getChild(i))), ns, Rule.DECLARATION));
00052 return l;
00053 }
00054
00055 @Override
00056 protected List<Source> visitFuncField(Node n) {
00057 List<Source> l = new LinkedList<Source>();
00058 for (int i = 0; i < n.getChildCount(); i++)
00059 l.add(new Source(trimQuotes(asText(n.getChild(i))), ns, Rule.DECLARATION, true));
00060 return l;
00061 }
00062
00063 @Override
00064 protected List<Source> visitSpecFile(String modifiers, String name, List<String> paramNames,
00065 List<List<Source>> specSources) {
00066 List<Source> src = new LinkedList<Source>();
00067 for (List<Source> l : specSources) {
00068 for (Source s : l) {
00069 String srcString = replaceParamTypes(s.source, paramNames);
00070 src.add(new Source(srcString, ns, s.rule));
00071 }
00072 }
00073 return src;
00074 }
00075
00076 private String replaceParamTypes(String source, List<String> paramNames) {
00077 String result = source;
00078 String[] typeParamNames = new String[paramNames.size()];
00079 Class<?> clz = jtype.clazz();
00080 if (clz.isArray()) {
00081 assert paramNames.size() == 1;
00082 Class<?> compType = clz.getComponentType();
00083 if (compType.isArray())
00084 typeParamNames[0] = escapeClsName(compType.getCanonicalName());
00085 else
00086 typeParamNames[0] = escapeClsName(compType.getName());
00087 } else {
00088 for (int i = 0; i < typeParamNames.length; i++) {
00089 if (i < jtype.typeParams().length) {
00090 typeParamNames[i] = escapeClsName(jtype.typeParams()[i].name());
00091 } else {
00092 typeParamNames[i] = "Object";
00093 }
00094 }
00095 }
00096 for (int i = 0; i < paramNames.size(); i++) {
00097 result = result.replaceAll("\\b" + paramNames.get(i) + "\\b", "(" + typeParamNames[i] + ")");
00098 }
00099 return result;
00100 }
00101
00102 private String escapeClsName(String name) {
00103 return name.replaceAll("\\$", "\\\\\\$");
00104 }
00105 }
00106
00107 @Override
00108 public List<Source> extractFieldSpec(Field field, JType.Unary declaringType) {
00109 return new LinkedList<Source>();
00110 }
00111
00112 @Override
00113 public MethodSpec extractMethodSpec(Method method, NameSpace ns) {
00114 return null;
00115 }
00116
00117 @Override
00118 public List<Source> extractClassSpec(JType.Unary jtype) {
00119 URL specFile = findSpecFile(jtype.clazz());
00120 if (specFile == null)
00121 return new LinkedList<Source>();
00122 Node n = parse(specFile);
00123 return new MyVisitor(jtype).visit(n);
00124 }
00125
00126 private URL findSpecFile(Class<?> clazz) {
00127 if (clazz == null)
00128 return null;
00129 if (clazz.isArray()) {
00130 URL url = ClassLoader.getSystemResource("java/lang/Object[].jfspec");
00131 assert url != null : "could not find specs for arrays";
00132 return url;
00133 }
00134 String resName = clazz.getName().replaceAll("\\.", "/") + ".jfspec";
00135 return ClassLoader.getSystemResource(resName);
00136 }
00137
00138 private Node parse(URL specFile) {
00139 try {
00140 SpecFileLexer lexer = new SpecFileLexer(new ANTLRInputStream(specFile.openStream()));
00141 CommonTokenStream tokens = new CommonTokenStream();
00142 tokens.setTokenSource(lexer);
00143 SpecFileParser parser = new SpecFileParser(tokens);
00144 TreeAdaptor adaptor = new SpecFileParser.NodeAdaptor();
00145 parser.setTreeAdaptor(adaptor);
00146 Object tree = parser.specfile().getTree();
00147 if (tree instanceof Node)
00148 return (Node) tree;
00149 throw new SpecFileParserException("Could not create AST: " + tree);
00150 } catch (IOException e) {
00151 throw new SpecFileParserException("Could not read input file", e);
00152 } catch (RecognitionException e) {
00153 throw new SpecFileParserException("Error parsing spec file", e);
00154 }
00155 }
00156
00157 }