/******************************************************************************* * Copyright (c) 2009-2012 CWI * 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: * * * Various members of the Software Analysis and Transformation Group - CWI * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI *******************************************************************************/ package org.rascalmpl.eclipse.terms; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IProgressMonitor; import org.rascalmpl.eclipse.Activator; import org.rascalmpl.eclipse.IRascalResources; import org.rascalmpl.eclipse.editor.MessagesToMarkers; import org.rascalmpl.eclipse.nature.RascalMonitor; import org.rascalmpl.eclipse.nature.WarningsToErrorLog; import org.rascalmpl.interpreter.IEvaluatorContext; import org.rascalmpl.interpreter.control_exceptions.MatchFailed; import org.rascalmpl.interpreter.control_exceptions.Throw; import org.rascalmpl.interpreter.result.ICallableValue; import org.rascalmpl.interpreter.types.RascalTypeFactory; import org.rascalmpl.interpreter.utils.ReadEvalPrintDialogMessages; import org.rascalmpl.interpreter.utils.RuntimeExceptionFactory; import org.rascalmpl.parser.gtd.exception.ParseError; import org.rascalmpl.parser.gtd.io.InputConverter; import org.rascalmpl.uri.ProjectURIResolver; import io.usethesource.vallang.IConstructor; import io.usethesource.vallang.ISet; import io.usethesource.vallang.ISetWriter; import io.usethesource.vallang.ISourceLocation; import io.usethesource.vallang.IValue; import io.usethesource.vallang.IValueFactory; import io.usethesource.vallang.type.Type; import io.usethesource.vallang.type.TypeFactory; import io.usethesource.impulse.builder.BuilderBase; import io.usethesource.impulse.builder.MarkerCreator; import io.usethesource.impulse.builder.MarkerCreatorWithBatching; import io.usethesource.impulse.language.Language; import io.usethesource.impulse.model.ISourceProject; import io.usethesource.impulse.model.ModelFactory; import io.usethesource.impulse.parser.IMessageHandler; import io.usethesource.impulse.runtime.PluginBase; public class Builder extends BuilderBase { private static final TermLanguageRegistry registry = TermLanguageRegistry.getInstance(); private static final TypeFactory TF = TypeFactory.getInstance(); private static final String MARKER_ID = IRascalResources.ID_TERM_MARKER; private static final MessagesToMarkers messagesToMarkers = new MessagesToMarkers(); private static final WarningsToErrorLog warnings = new WarningsToErrorLog(); @Override protected PluginBase getPlugin() { return Activator.getInstance(); } @Override protected boolean isSourceFile(IFile file) { return registry.getLanguage(file.getFileExtension()) != null; } @Override protected boolean isNonRootSourceFile(IFile file) { return false; } @Override protected boolean isOutputFolder(IResource resource) { return resource.getFullPath().lastSegment().equals("bin"); } @Override protected void compile(IFile file, IProgressMonitor monitor) { InputStream contents = null; String input = null; IMessageHandler handler = new MarkerCreator(file, MARKER_ID); Language lang = registry.getLanguage(file.getFileExtension()); ISet builders = registry.getBuilders(lang); IEvaluatorContext evalForErrors = null; if (builders == null || builders.size() == 0) { return; } try { ICallableValue parser = registry.getParser(lang); evalForErrors = parser.getEval(); RascalMonitor rmonitor = new RascalMonitor(monitor, warnings); IValueFactory VF = parser.getEval().getValueFactory(); ISourceProject project = ModelFactory.open(file.getProject()); ISourceLocation loc = ProjectURIResolver.constructProjectURI(project.getRawProject(), file.getProjectRelativePath()); contents = file.getContents(); input = new String(InputConverter.toChar(contents, Charset.forName(file.getCharset()))); IConstructor tree; synchronized (parser.getEval()) { tree = (IConstructor) parser.call(rmonitor, new Type[] {TF.stringType(), TF.sourceLocationType()}, new IValue[] { VF.string(input), loc}, null).getValue(); } ISetWriter messages = VF.setWriter(); Type type = RascalTypeFactory.getInstance().nonTerminalType(tree); for (IValue elem : builders) { IConstructor container = (IConstructor) elem; ICallableValue builder = (ICallableValue) container.get("messages"); ISet result = null; synchronized (builder.getEval()) { try { result = (ISet) builder.call(rmonitor, new Type[] { type }, new IValue[] { tree }, null).getValue(); } catch (MatchFailed e) { builder.getEval().getStdErr().write("builder function can not handle tree of type:" + type + "\n"); builder.getEval().getStdErr().write(e.toString() + "\n"); builder.getEval().getStdErr().flush(); } } if (result != null) { messages.insertAll(result); } } messagesToMarkers.process(loc, messages.done(), handler); handler.endMessages(); // TODO: this MarkerCreatorWithBatching should just implement endMessages() correctly. if (handler instanceof MarkerCreatorWithBatching) { ((MarkerCreatorWithBatching) handler).flush(monitor); } } catch (ParseError pe){ int offset = pe.getOffset(); if(offset == input.length()) --offset; handler.handleSimpleMessage("parse error", offset, offset + pe.getLength(), pe.getBeginColumn(), pe.getEndColumn(), pe.getBeginLine() + 1, pe.getEndLine() + 1); } catch (Throw e) { IValue exc = e.getException(); if (exc.getType() == RuntimeExceptionFactory.Exception) { if (((IConstructor) exc).getConstructorType() == RuntimeExceptionFactory.ParseError) { ISourceLocation loc = (ISourceLocation) ((IConstructor) e.getException()).get(0); handler.handleSimpleMessage("builder error: " + loc, loc.getOffset(), loc.getOffset() + loc.getLength(), loc.getBeginColumn(), loc.getEndColumn(), loc.getBeginLine(), loc.getEndLine()); } else if (evalForErrors != null) { evalForErrors.getStdErr().write(ReadEvalPrintDialogMessages.throwMessage(e) + "\n"); evalForErrors.getStdErr().flush(); } else { Activator.getInstance().logException(e.getMessage(), e); } } else { if (evalForErrors != null) { evalForErrors.getStdErr().write(ReadEvalPrintDialogMessages.throwMessage(e) + "\n"); evalForErrors.getStdErr().flush(); } else { Activator.getInstance().logException(exc.toString(), e); } } } catch (IOException e) { String error = "could not read file in builder: " + file; if (evalForErrors != null) { evalForErrors.getStdErr().write(error + "\n"); evalForErrors.getStdErr().write(e.toString() + "\n"); evalForErrors.getStdErr().flush(); } else Activator.getInstance().logException("could not read file in builder: " + file, e); return; } catch (Throwable e) { Activator.getInstance().logException("exception in builder for: " + file, e); } finally { if (contents != null) { try { contents.close(); } catch (IOException e) { Activator.getInstance().logException("exception in builder for: " + file, e); } } } } @Override protected void collectDependencies(IFile file) { // nothing for now } @Override protected String getErrorMarkerID() { return MARKER_ID; } @Override protected String getWarningMarkerID() { return MARKER_ID; } @Override protected String getInfoMarkerID() { return MARKER_ID; } }