/* * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package org.visage.tools.main; import com.sun.source.tree.Tree.Kind; import com.sun.source.util.TaskEvent; import org.visage.tools.tree.BlockExprJCBlockExpression; import com.sun.tools.mjavac.comp.AttrContext; import com.sun.tools.mjavac.comp.Env; import com.sun.tools.mjavac.main.*; import com.sun.tools.mjavac.tree.JCTree.JCClassDecl; import com.sun.tools.mjavac.tree.JCTree.JCCompilationUnit; import com.sun.tools.mjavac.util.*; import org.visage.tools.util.VisageBackendLog; import com.sun.tools.mjavac.parser.Parser; import com.sun.tools.mjavac.parser.Scanner; import com.sun.tools.mjavac.parser.Token; import com.sun.tools.mjavac.tree.JCTree; import com.sun.tools.mjavac.tree.JCTree.JCBlock; import com.sun.tools.mjavac.tree.JCTree.JCExpression; import com.sun.tools.mjavac.tree.JCTree.JCExpressionStatement; import com.sun.tools.mjavac.tree.JCTree.JCStatement; import static com.sun.tools.mjavac.parser.Token.*; import java.io.IOException; import java.lang.reflect.Field; import javax.annotation.processing.Processor; import javax.tools.JavaFileObject; /** * * @author Robert */ public class VisageJavaCompiler extends JavaCompiler { /** The context key for the compiler. */ protected static final Context.Key<VisageJavaCompiler> visageJavaCompilerKey = new Context.Key<VisageJavaCompiler>(); List<JCCompilationUnit> modules; // Current compilation final VisageBackendLog beLog; /** Get the JavaCompiler instance for this context. */ public static VisageJavaCompiler instance(Context context) { VisageJavaCompiler instance = context.get(visageJavaCompilerKey); if (instance == null) instance = new VisageJavaCompiler(context); return instance; } protected VisageJavaCompiler(Context context) { super(context); Log log = Log.instance(context); beLog = (log instanceof VisageBackendLog)? (VisageBackendLog)log : null; } @Override public void initProcessAnnotations(Iterable<? extends Processor> arg0) { // Visage doesn't support annotations } public void backEnd(List<JCCompilationUnit> externalModules, ListBuffer<JavaFileObject> results) throws IOException { modules = externalModules; this.results = results; compile(null, List.<String>nil(), null); this.results = null; } public Name.Table getNames() { return names; } public Env<AttrContext> attribute(Env<AttrContext> env) { try { if (beLog != null) { beLog.env = env; } super.attribute(env); } finally { if (beLog != null) { beLog.env = null; } } return env; } /** * Override of JavaCompiler.generate() to catch list of generated class files. * Do not call directly. */ @Override public void generate(List<Pair<Env<AttrContext>, JCClassDecl>> list) { generate(list, results); } ListBuffer<JavaFileObject> results = null; @Override public List<JCCompilationUnit> parseFiles(List<JavaFileObject> fileObjects) throws IOException { if (modules != null) { return modules; } else { return super.parseFiles(fileObjects); } } @Override protected JCCompilationUnit parse(JavaFileObject filename, CharSequence content) { // The following code is cut-pasted (ugly!) from super class and edited to // override parser. The parser change here is to support block expressions. long msec = System.currentTimeMillis(); JCCompilationUnit tree = make.TopLevel(List.<JCTree.JCAnnotation>nil(), null, List.<JCTree>nil()); if (content != null) { if (verbose) { printVerbose("parsing.started", filename); } if (taskListener != null) { TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, filename); taskListener.started(e); } int initialErrorCount = log.nerrors; final Scanner scanner = getScannerFactory().newScanner(content); // This was: Parser parser = parserFactory.newParser(scanner, keepComments(), genEndPos); Parser parser = new Parser(parserFactory, scanner, keepComments()) { @Override public JCExpression expression() { Token next = scanner.token(); if (next == LBRACE) { return parseBlockExpression(); } else { scanner.token(next); return super.expression(); } } @Override protected JCExpression term3() { Token next = scanner.token(); if (next == LBRACE) { return parseBlockExpression(); } else { scanner.token(next); return super.term3(); } } @Override protected JCExpression checkExprStat(JCExpression t) { // Block expressions can have last expressions that are not valid // Java expressions! So, don't check for validity. return t; } private JCExpression parseBlockExpression() { JCBlock blk = block(); List<JCStatement> stats = blk.getStatements(); JCExpression value = null; JCStatement lastStat = stats.last(); ListBuffer<JCStatement> newStats = new ListBuffer<JCStatement>(); final int count = stats.size(); int index = 1; for (JCStatement s : stats) { // Is this the last statement? if (index == count) { lastStat = s; break; } newStats.append(s); index++; } if (lastStat != null && lastStat.getKind() == Kind.EXPRESSION_STATEMENT) { stats = newStats.toList(); value = ((JCExpressionStatement)lastStat).getExpression(); } JCExpression expr = new BlockExprJCBlockExpression(0L, stats, value); expr.pos = blk.pos; return expr; } }; tree = parser.compilationUnit(); // HACK: Need to set parseErrors flag in superclass which is private! // Use reflection hack to set right value of parseErrors flag. setParseErrors(log.nerrors > initialErrorCount); if (lineDebugInfo) { tree.lineMap = scanner.getLineMap(); } if (verbose) { printVerbose("parsing.done", Long.toString(System.currentTimeMillis() - msec)); } } tree.sourcefile = filename; if (content != null && taskListener != null) { TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, tree); taskListener.finished(e); } return tree; } // where private void setParseErrors(boolean newValue) { try { Field parseErrorsField = JavaCompiler.class.getDeclaredField("parseErrors"); parseErrorsField.setAccessible(true); boolean oldValue = parseErrorsField.getBoolean(this); parseErrorsField.setBoolean(this, oldValue |= newValue); } catch (Exception ignored) { } } }