/******************************************************************************* * Copyright (c) 2006 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * *******************************************************************************/ package org.rubypeople.rdt.core.compiler; import java.util.Collection; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.jruby.ast.CommentNode; import org.jruby.ast.Node; import org.jruby.lexer.yacc.SyntaxException; import org.jruby.parser.RubyParserResult; import org.rubypeople.rdt.core.IRubyScript; import org.rubypeople.rdt.core.RubyCore; import org.rubypeople.rdt.internal.core.builder.SyntaxExceptionHandler; import org.rubypeople.rdt.internal.core.parser.RubyParser; import org.rubypeople.rdt.internal.core.util.Util; /** * The context of a build event that is notified to interested compilation participants when * {@link CompilationParticipant#buildStarting(BuildContext[], boolean) a build is starting}, or to annotations * processors when {@link CompilationParticipant#processAnnotations(BuildContext[]) a source file has annotations}. * <p> * This class is not intended to be instanciated or subclassed by clients. * </p> * * @since 0.9.0 */ public class BuildContext extends CompilationParticipantResult { private RubyParserResult ast; private boolean alreadyFailed; // to avoid re-parsing file that throws syntax exceptions during parse /** * Creates a build context for the given source file. * <p> * This constructor is not intended to be called by clients. * </p> * * @param sourceFile * the source file being built */ public BuildContext(IFile resource) { super(resource); } /** * Returns the contents of the compilation unit. * * @return the contents of the compilation unit */ public char[] getContents() { try { return Util.getResourceContentsAsCharArray(this.resource); } catch (CoreException e) { throw new RuntimeException("Missing source file: " + this.resource); } } /** * Returns the <code>IFile</code> representing the compilation unit. * * @return the <code>IFile</code> representing the compilation unit */ public IFile getFile() { return this.resource; } /** * Returns whether the compilation unit contained any annotations when it was compiled. NOTE: This is only valid * during {@link CompilationParticipant#processAnnotations(BuildContext[])}. * * @return whether the compilation unit contained any annotations when it was compiled */ public boolean hasAnnotations() { return this.hasAnnotations; // only set during processAnnotations } /** * Record new problems to report against this compilationUnit. Markers are persisted for these problems only for the * declared managed marker type (see the 'compilationParticipant' extension point). * * @param newProblems * the problems to report */ public void recordNewProblems(CategorizedProblem[] newProblems) { int length2 = newProblems.length; if (length2 == 0) return; int length1 = this.problems == null ? 0 : this.problems.length; CategorizedProblem[] merged = new CategorizedProblem[length1 + length2]; if (length1 > 0) // always make a copy even if currently empty System.arraycopy(this.problems, 0, merged, 0, length1); System.arraycopy(newProblems, 0, merged, length1, length2); this.problems = merged; } public Node getAST() { if (ast == null) { lazilyParse(); } if (ast == null) return null; return ast.getAST(); } private void lazilyParse() { if (alreadyFailed) return; String contents = new String(getContents()); try { IRubyScript script = RubyCore.create(getFile()); ast = new RubyParser().parse(script.getPath().toPortableString(), contents); } catch (SyntaxException se) { recordNewProblems(new CategorizedProblem[] { SyntaxExceptionHandler.handle(se, contents) }); alreadyFailed = true; } catch (Exception e) { alreadyFailed = true; } } public Collection<CommentNode> getComments() { if (ast == null) { lazilyParse(); } if (ast == null) return null; return ast.getCommentNodes(); } }