/******************************************************************************* * Copyright (c) 2009-2011 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: * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI * * Tijs van der Storm - Tijs.van.der.Storm@cwi.nl * * Mark Hills - Mark.Hills@cwi.nl (CWI) * * Arnold Lankamp - Arnold.Lankamp@cwi.nl *******************************************************************************/ package org.rascalmpl.eclipse.terms; import java.io.PrintWriter; import org.rascalmpl.eclipse.Activator; import org.rascalmpl.eclipse.editor.MessagesToAnnotations; import org.rascalmpl.interpreter.control_exceptions.Throw; import org.rascalmpl.interpreter.result.ICallableValue; import org.rascalmpl.interpreter.staticErrors.StaticError; import org.rascalmpl.interpreter.types.RascalTypeFactory; import org.rascalmpl.interpreter.utils.ReadEvalPrintDialogMessages; import org.rascalmpl.parser.gtd.exception.ParseError; import io.usethesource.vallang.IConstructor; import io.usethesource.vallang.IList; import io.usethesource.vallang.IValue; import io.usethesource.vallang.type.Type; import org.rascalmpl.values.uptr.ITree; import org.rascalmpl.values.uptr.TreeAdapter; import io.usethesource.impulse.parser.IMessageHandler; /** * This class connects the Eclipse IDE with Rascal functions that annotate parse trees. * * It makes sure these annotator functions are called after each successful parse. * After proper annotations have been added, features such as documentation tooltips * and hyperlinking uses to definitions start working. * * Note that this class only works for languages that have been registered using the * API in SourceEditor.rsc */ public class AnnotatorExecutor { private final MessagesToAnnotations marker = new MessagesToAnnotations(); public synchronized ITree annotate(ICallableValue func, ITree parseTree, IMessageHandler handler) { try { ITree top = parseTree; boolean start = false; IConstructor tree; if (TreeAdapter.isAppl(top) && TreeAdapter.getSortName(top).equals("<START>")) { tree = (IConstructor) TreeAdapter.getArgs(top).get(1); start = true; } else { tree = top; } Type type = RascalTypeFactory.getInstance().nonTerminalType(tree); ITree newTree; synchronized(func.getEval()){ func.getEval().__setInterrupt(false); newTree = (ITree) func.call(new Type[] {type}, new IValue[] {tree}, null).getValue(); } if (newTree != null) { if (start) { IList newArgs = TreeAdapter.getArgs(top).put(1, newTree); newTree = (ITree) top.set("args", newArgs).asAnnotatable().setAnnotation("loc", top.asAnnotatable().getAnnotation("loc")); } marker.process(newTree, handler); return newTree; } else { Activator.getInstance().logException("annotator returned null", new RuntimeException()); } } catch (RuntimeException e) { if (e instanceof ParseError || e instanceof StaticError || e instanceof Throw) { PrintWriter stdErr = func.getEval().getStdErr(); stdErr.write("Annotator failed\n"); stdErr.write(ReadEvalPrintDialogMessages.parseOrStaticOrThrowMessage(e)); stdErr.flush(); } else { Activator.getInstance().logException("annotater failed", e); } } catch (Throwable e) { Activator.getInstance().logException("annotater failed", e); } return null; } }