/*******************************************************************************
* Copyright (c) 2009-2013 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
* * Paul Klint - Paul.Klint@cwi.nl - CWI
* * Arnold Lankamp - Arnold.Lankamp@cwi.nl
*******************************************************************************/
package org.rascalmpl.interpreter.control_exceptions;
import java.io.IOException;
import org.rascalmpl.ast.AbstractAST;
import org.rascalmpl.interpreter.StackTrace;
import org.rascalmpl.interpreter.utils.LimitedResultWriter;
import org.rascalmpl.interpreter.utils.LimitedResultWriter.IOLimitReachedException;
import org.rascalmpl.value.ISourceLocation;
import org.rascalmpl.value.IValue;
import org.rascalmpl.value.io.StandardTextWriter;
/**
* This class is for representing all run-time exceptions in Rascal.
* These exceptions can be caught by Rascal code.
* These exceptions can be thrown by either the Rascal interpreter -
* in case of a run-time error, or by Rascal code - using the throw statement,
* or by Java "built-in" methods, or by Java "embedded" methods.
* <br>
* Note that this class is <code>final</code> to emphasize the fact that
* different kinds of Rascal exceptions need to be modeled by different kind
* of exception values, not different kind of Java classes.
*/
public final class Throw extends ControlException {
private static final long serialVersionUID = -7290501865940548332L;
private final IValue exception;
private volatile ISourceLocation loc;
private volatile StackTrace trace;
private static String toString(IValue value, int length){
StandardTextWriter stw = new StandardTextWriter(true);
LimitedResultWriter lros = new LimitedResultWriter(length);
try {
stw.write(value, lros);
}
catch (IOLimitReachedException iolrex){
// This is fine, ignore.
}
catch (IOException ioex) {
// This can never happen.
}
return lros.toString();
}
// It is *not* the idea that these exceptions store references to AbstractAST's!
/**
* Make a new Rascal exception.
*
* @param value The Rascal exception value
* @param loc A source location, or null if unavailable
* @param trace A stack trace, or null
*/
public Throw(IValue value, ISourceLocation loc, StackTrace trace) {
super(toString(value, 4096));
this.exception = value;
this.loc = loc;
if(trace == null) {
trace = StackTrace.EMPTY_STACK_TRACE;
}
this.trace = trace;
}
// It is *not* the idea that these exceptions store references to AbstractAST's!
/**
* Make a new Rascal exception.
*
* The AbstractAST (if non-null) is used to find the current source location.
*
* @param value The Rascal exception value
* @param ast An AbstractAST, or null
* @param trace A stack trace, or null
*/
public Throw(IValue value, AbstractAST ast, StackTrace trace) {
this(value, ast != null ? ast.getLocation() : null, trace);
}
/**
* @return The Rascal stack trace, guaranteed to never be null
*/
public StackTrace getTrace() {
return trace;
}
/**
* Update the Rascal stack trace.
*
* @param trace The new trace, or null for an empty trace
*/
public void setTrace(StackTrace trace) {
if(trace == null) {
trace = StackTrace.EMPTY_STACK_TRACE;
}
this.trace = trace;
}
/**
* @return The Rascal exception value
*/
public IValue getException() {
return exception;
}
/**
* @return The source location where this exception occurred, or null
*/
public ISourceLocation getLocation() {
return loc;
}
/**
* @param loc The source location, or null
*/
public void setLocation(ISourceLocation loc) {
this.loc = loc;
}
@Override
public Throwable fillInStackTrace() {
return reallyFillInStackTrace(); // ensure that we have proper Java traces as well
}
@Override
public String getMessage() {
if (loc != null) {
return (loc.getScheme().equals("file") ? (loc.getAuthority() + loc.getPath()) : loc.top())
+ ":" + loc.getBeginLine()
+ "," + loc.getBeginColumn()
+ ": " + super.getMessage();
}
// TODO remove once all errors have locations
return super.getMessage();
}
}