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 }