001: package spoon.support.builder;
002:
003: import java.io.ByteArrayOutputStream;
004: import java.io.PrintWriter;
005: import java.util.ArrayList;
006: import java.util.Set;
007: import java.util.TreeSet;
008:
009: import spoon.processing.Builder;
010: import spoon.reflect.Factory;
011: import spoon.reflect.code.CtBlock;
012: import spoon.reflect.code.CtCodeSnippetExpression;
013: import spoon.reflect.code.CtCodeSnippetStatement;
014: import spoon.reflect.code.CtExpression;
015: import spoon.reflect.code.CtReturn;
016: import spoon.reflect.code.CtStatement;
017: import spoon.reflect.declaration.CtClass;
018: import spoon.reflect.declaration.CtMethod;
019: import spoon.reflect.declaration.CtParameter;
020: import spoon.reflect.declaration.CtSimpleType;
021: import spoon.reflect.declaration.CtType;
022: import spoon.reflect.declaration.ModifierKind;
023: import spoon.reflect.reference.CtTypeReference;
024: import spoon.reflect.visitor.Filter;
025: import spoon.reflect.visitor.Query;
026: import spoon.support.builder.support.CtVirtualFile;
027:
028: public class SnippetCompiler {
029:
030: @SuppressWarnings("unchecked")
031: static public <T> T compileStatement(CtCodeSnippetStatement st,
032: Class<T> expectedType) throws CtSnippetCompilationError {
033: CtStatement s = compileStatement(st);
034: if (expectedType.isAssignableFrom(s.getClass())) {
035: return (T) s;
036: }
037: throw new CtSnippetCompilationError(
038: "Incorrect Type for snippet " + st.toString());
039: }
040:
041: static public void compileAndReplaceSnippetsIn(CtSimpleType<?> c) {
042: Factory f = c.getFactory();
043: CtSimpleType<?> workCopy = c;
044: Set<ModifierKind> backup = new TreeSet<ModifierKind>(workCopy
045: .getModifiers());
046:
047: workCopy.getModifiers().remove(ModifierKind.PUBLIC);
048:
049: try {
050: build(f, workCopy.toString());
051: } finally {
052: // restore modifiers
053: c.setModifiers(backup);
054: }
055:
056: }
057:
058: static public CtStatement compileStatement(CtCodeSnippetStatement st)
059: throws CtSnippetCompilationError {
060:
061: return internalCompileStatement(st);
062: }
063:
064: private static CtStatement internalCompileStatement(CtStatement st) {
065: Factory f = st.getFactory();
066: CtClass<?> w = createWrapper(st, f);
067:
068: compile(f, w);
069:
070: CtSimpleType<?> c = f.Type().get("Wrapper");
071:
072: // Get the part we want
073:
074: CtMethod<?> wrapper = Query.getElements(c,
075: new Filter<CtMethod<?>>() {
076:
077: @SuppressWarnings("unchecked")
078: public Class<CtMethod<?>> getType() {
079: try {
080: return (Class<CtMethod<?>>) Class
081: .forName(CtMethod.class.getName());
082: } catch (Exception e) {
083: e.printStackTrace();
084: return null;
085: }
086: }
087:
088: public boolean matches(CtMethod<?> element) {
089: return element.getSimpleName().equals("wrap");
090: }
091:
092: }).get(0);
093:
094: CtStatement ret = wrapper.getBody().getStatements().get(0);
095: // Clean up
096:
097: c.getPackage().getTypes().remove(c);
098:
099: // check typing?
100:
101: return ret;
102: }
103:
104: private static CtClass<?> createWrapper(CtStatement st, Factory f) {
105: CtClass<?> w = f.Class().create("Wrapper");
106:
107: CtBlock<Void> body = f.Core().createBlock();
108:
109: body.getStatements().add(st);
110:
111: Set<ModifierKind> x = new TreeSet<ModifierKind>();
112:
113: f.Method().create(w, x, f.Type().createReference(void.class),
114: "wrap", new ArrayList<CtParameter<?>>(),
115: new TreeSet<CtTypeReference<? extends Throwable>>(),
116: body);
117:
118: return w;
119: }
120:
121: private static void compile(Factory f, CtType<?> w)
122: throws CtSnippetCompilationError {
123:
124: String contents = w.toString();
125:
126: build(f, contents);
127:
128: }
129:
130: private static void build(Factory f, String contents, String name) {
131: // Build contents
132: boolean success;
133: Builder builder = new SnippetBuilder(f);
134: try {
135: builder.addInputSource(new CtVirtualFile(contents, name));
136: success = builder.build();
137: } catch (Exception e) {
138: success = debugCompilationError(f, e);
139: }
140:
141: if (!success) {
142: throw new CtSnippetCompilationError(builder.getProblems());
143: }
144: }
145:
146: private static void build(Factory f, String contents)
147: throws CtSnippetCompilationError {
148: build(f, contents, "");
149: }
150:
151: private static boolean debugCompilationError(Factory f, Exception e) {
152: boolean success;
153: f.getEnvironment().debugMessage("BORKED SnippetCompilation");
154: ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
155: PrintWriter pw = new PrintWriter(byteArrayOutputStream);
156: e.printStackTrace(pw);
157: String s = new String(byteArrayOutputStream.toByteArray());
158: f.getEnvironment().debugMessage(s);
159: success = false;
160: return success;
161: }
162:
163: @SuppressWarnings("unchecked")
164: static public <T> CtExpression<T> compileExpression(
165: CtCodeSnippetExpression<T> expr)
166: throws CtSnippetCompilationError {
167: // create wrapping template
168:
169: Factory f = expr.getFactory();
170: CtClass<?> w = createWrapper(expr, f);
171:
172: String contents = w.toString();
173:
174: build(f, contents);
175:
176: CtSimpleType c = f.Type().get("Wrapper");
177:
178: // Get the part we want
179:
180: CtMethod wrapper = Query.getElements(c, new Filter<CtMethod>() {
181:
182: public Class<CtMethod> getType() {
183: return CtMethod.class;
184: }
185:
186: public boolean matches(CtMethod element) {
187: return element.getSimpleName().equals("wrap");
188: }
189:
190: }).get(0);
191:
192: CtReturn<T> ret = (CtReturn<T>) wrapper.getBody()
193: .getStatements().get(0);
194:
195: // Clean up (delete wrapper from factory)
196: c.getPackage().getTypes().remove(c);
197:
198: return ret.getReturnedExpression();
199: }
200:
201: private static <R, B extends R> CtClass<?> createWrapper(
202: CtExpression<B> st, Factory f) {
203: CtClass<?> w = f.Class().create("Wrapper");
204:
205: CtBlock<B> body = f.Core().createBlock();
206: CtReturn<B> ret = f.Core().createReturn();
207: ret.setReturnedExpression(st);
208: body.getStatements().add(ret);
209:
210: Set<ModifierKind> x = new TreeSet<ModifierKind>();
211:
212: f.Method().create(w, x, f.Type().createReference(Object.class),
213: "wrap", new ArrayList<CtParameter<?>>(),
214: new TreeSet<CtTypeReference<? extends Throwable>>(),
215: body);
216:
217: return w;
218: }
219:
220: }
|