/******************************************************************************* * 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: * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI * * Anya Helene Bagge - A.H.S.Bagge@cwi.nl (Univ. Bergen) * * Paul Klint - Paul.Klint@cwi.nl - CWI * * Arnold Lankamp - Arnold.Lankamp@cwi.nl * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI *******************************************************************************/ package org.rascalmpl.eclipse.terms; import java.util.Iterator; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.rascalmpl.eclipse.Activator; import org.rascalmpl.eclipse.editor.NodeLocator; import org.rascalmpl.eclipse.editor.TokenIterator; import org.rascalmpl.eclipse.nature.IWarningHandler; import org.rascalmpl.eclipse.nature.RascalMonitor; import org.rascalmpl.eclipse.nature.WarningsToMessageHandler; import org.rascalmpl.interpreter.control_exceptions.Throw; import org.rascalmpl.interpreter.result.ICallableValue; import org.rascalmpl.interpreter.utils.RuntimeExceptionFactory; import org.rascalmpl.parser.gtd.exception.ParseError; import org.rascalmpl.uri.ProjectURIResolver; import org.rascalmpl.uri.file.FileURIResolver; import io.usethesource.vallang.IConstructor; import io.usethesource.vallang.ISourceLocation; import io.usethesource.vallang.IValue; import io.usethesource.vallang.IValueFactory; import io.usethesource.vallang.exceptions.FactTypeUseException; import io.usethesource.vallang.type.Type; import io.usethesource.vallang.type.TypeFactory; import org.rascalmpl.values.ValueFactoryFactory; import org.rascalmpl.values.uptr.ITree; import io.usethesource.impulse.language.Language; import io.usethesource.impulse.model.ISourceProject; import io.usethesource.impulse.parser.IMessageHandler; import io.usethesource.impulse.parser.IParseController; import io.usethesource.impulse.parser.ISourcePositionLocator; import io.usethesource.impulse.services.IAnnotationTypeInfo; import io.usethesource.impulse.services.ILanguageSyntaxProperties; public class TermParseController implements IParseController { private ISourceProject project; private IConstructor parseTree; private IPath path; private Language language; private IDocument document; private ParseJob job; private final static IValueFactory VF = ValueFactoryFactory.getValueFactory(); private final static AnnotatorExecutor executor = new AnnotatorExecutor(); public Object getCurrentAst(){ return parseTree; } public void setCurrentAst(IConstructor parseTree) { this.parseTree = parseTree; } public IAnnotationTypeInfo getAnnotationTypeInfo() { return null; } public Language getLanguage() { return language; } public IPath getPath() { return path; } public ISourceProject getProject() { return project; } public ISourcePositionLocator getSourcePositionLocator() { return new NodeLocator(); } public ILanguageSyntaxProperties getSyntaxProperties() { IConstructor syntaxProperties = TermLanguageRegistry.getInstance().getSyntaxProperties(getLanguage()); return syntaxProperties != null ? new TermLanguageSyntaxProperties(syntaxProperties) : null; } public Iterator<Object> getTokenIterator(IRegion region) { return new TokenIterator(true, parseTree); } @Override public void initialize(IPath filePath, ISourceProject project, IMessageHandler handler) { Assert.isTrue(filePath.isAbsolute() && project == null || !filePath.isAbsolute() && project != null); this.path = filePath; this.project = project; TermLanguageRegistry reg = TermLanguageRegistry.getInstance(); this.language = reg.getLanguage(path.getFileExtension()); ISourceLocation location = null; if (project != null) { location = ProjectURIResolver.constructProjectURI(project.getRawProject(), path); } else { location = FileURIResolver.constructFileURI(path.toOSString()); } this.job = new ParseJob(language.getName() + " parser", location, handler); } public IDocument getDocument() { return document; } public Object parse(IDocument doc, IProgressMonitor monitor) { if (doc == null) { return null; } this.document = doc; return parse(doc.get(), monitor); } private class ParseJob extends Job { private final IMessageHandler handler; private final IWarningHandler warnings; private final ISourceLocation loc; private String input; public ITree parseTree = null; public ParseJob(String name, ISourceLocation loc, IMessageHandler handler) { super(name); this.loc = loc; this.handler = handler; this.warnings = new WarningsToMessageHandler(loc, handler); } public void initialize(String input) { this.input = input; } @Override protected IStatus run(IProgressMonitor monitor) { RascalMonitor rm = new RascalMonitor(monitor, warnings); rm.startJob("Parsing Term", 105); try{ handler.clearMessages(); TypeFactory TF = TypeFactory.getInstance(); ICallableValue parser = getParser(); if (parser != null) { synchronized (parser.getEval()) { parseTree = (ITree) parser.call(rm, new Type[] {TF.stringType(), TF.sourceLocationType()}, new IValue[] { VF.string(input), loc}, null).getValue(); } ICallableValue annotator = getAnnotator(); if (parseTree != null && annotator != null) { rm.event("annotating", 5); ITree newTree = executor.annotate(annotator, parseTree, handler); if (newTree != null) { parseTree = newTree; } } } } 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); parseTree = null; handler.handleSimpleMessage("parse error: " + loc, loc.getOffset(), loc.getOffset() + loc.getLength(), loc.getBeginColumn(), loc.getEndColumn(), loc.getBeginLine(), loc.getEndLine()); } else { Activator.getInstance().logException(e.getMessage(), e); } } } catch (FactTypeUseException ftuex) { Activator.getInstance().logException("parsing " + language.getName() + " failed", ftuex); } catch (NullPointerException npex){ Activator.getInstance().logException("parsing " + language.getName() + " failed", npex); } catch (Throwable e) { Activator.getInstance().logException("parsing " + language.getName() + " failed: " + e.getMessage(), e); } finally { rm.endJob(true); } return Status.OK_STATUS; } private ICallableValue getAnnotator() { return TermLanguageRegistry.getInstance().getAnnotator(language); } private ICallableValue getParser() { return TermLanguageRegistry.getInstance().getParser(language); } } public synchronized Object parse(String input, IProgressMonitor monitor){ parseTree = null; try { job.initialize(input); job.schedule(); job.join(); parseTree = job.parseTree; return parseTree; } catch (InterruptedException e) { Activator.getInstance().logException("parser interrupted", e); } return null; } }