/*******************************************************************************
* 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
* * Emilie Balland - (CWI)
* * Arnold Lankamp - Arnold.Lankamp@cwi.nl
* * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI
*******************************************************************************/
package org.rascalmpl.eclipse.debug.core.model;
import java.io.IOException;
import java.io.Writer;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IValue;
import org.eclipse.debug.core.model.IVariable;
import org.rascalmpl.interpreter.types.RascalTypeFactory;
import org.rascalmpl.interpreter.utils.LimitedResultWriter;
import org.rascalmpl.interpreter.utils.LimitedResultWriter.IOLimitReachedException;
import io.usethesource.vallang.IConstructor;
import io.usethesource.vallang.IList;
import io.usethesource.vallang.IMap;
import io.usethesource.vallang.INode;
import io.usethesource.vallang.ISet;
import io.usethesource.vallang.ITuple;
import io.usethesource.vallang.io.StandardTextWriter;
import io.usethesource.vallang.type.ITypeVisitor;
import io.usethesource.vallang.type.Type;
import io.usethesource.vallang.type.TypeFactory;
import org.rascalmpl.values.uptr.ITree;
import org.rascalmpl.values.uptr.ProductionAdapter;
import org.rascalmpl.values.uptr.RascalValueFactory;
import org.rascalmpl.values.uptr.SymbolAdapter;
import org.rascalmpl.values.uptr.TreeAdapter;
public class RascalValue extends RascalDebugElement implements IValue {
/* do not print more than MAX_VALUE_STRING characters */
private final static int MAX_VALUE_STRING = 1000;
private final RascalStackFrame target;
private final io.usethesource.vallang.IValue value;
private final Type decl;
private IVariable[] children = null;
public RascalValue(RascalStackFrame target, Type decl, io.usethesource.vallang.IValue value) {
super(target.getRascalDebugTarget());
this.value = value;
this.decl = decl;
this.target = target;
}
public io.usethesource.vallang.IValue getRuntimeValue() {
return value;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IValue#getReferenceTypeName()
*/
public String getReferenceTypeName() throws DebugException {
return value.getType().toString();
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IValue#getValueString()
*/
public String getValueString() throws DebugException {
if (value == null) {
return "<uninitialized>";
}
if (value.getType().isSubtypeOf(RascalValueFactory.Tree)) {
return getTreeValueString();
}
return getNormalValueString();
}
private String getNormalValueString() {
Writer w = new LimitedResultWriter(MAX_VALUE_STRING);
try {
new StandardTextWriter(true, 2).write(value, w);
return w.toString();
} catch (IOLimitReachedException e) {
return w.toString();
}
catch (IOException e) {
return "error during serialization...";
}
}
private String getTreeValueString() {
StringBuilder b = new StringBuilder();
ITree tree = (ITree) value;
if (TreeAdapter.isChar(tree)) {
return TreeAdapter.yield(tree, MAX_VALUE_STRING);
}
IConstructor type = TreeAdapter.getType(tree);
b.append(SymbolAdapter.toString(type, false));
String cons = null;
if (TreeAdapter.isAppl(tree)) {
cons = TreeAdapter.getConstructorName(tree);
}
else if (TreeAdapter.isAmb(tree)) {
cons = "amb";
}
if (cons != null) {
b.append(' ');
b.append(cons);
}
b.append(':');
b.append('`');
b.append(TreeAdapter.yield(tree, MAX_VALUE_STRING));
b.append('`');
b.append("\n");
b.append(getNormalValueString());
return b.toString();
}
public IVariable[] getVariables() throws DebugException {
return null;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IValue#getVariables()
*/
public IVariable[] getVariables2() throws DebugException {
if (children != null) {
return children.clone();
}
TypeFactory tf = TypeFactory.getInstance();
final Type vt = tf.valueType();
if (value == null) {
return null;
}
return children = value.getType().accept(new ITypeVisitor<IVariable[], RuntimeException>() {
@Override
public IVariable[] visitReal(Type type) {
return new IVariable[0];
}
@Override
public IVariable[] visitInteger(Type type) {
return new IVariable[0];
}
@Override
public IVariable[] visitRational(Type type) {
return new IVariable[0];
}
@Override
public IVariable[] visitList(Type type) {
IList list = (IList) value;
IVariable[] result = new IVariable[list.length()];
for (int i = 0; i < list.length(); i++) {
result[i] = new RascalVariable(target, "[" + i + "]", decl.isList() ? decl.getElementType() : list.getElementType(), list.get(i));
}
return result;
}
@Override
public IVariable[] visitMap(Type type) {
IMap map = (IMap) value;
IVariable[] result = new IVariable[map.size()];
int i = 0;
for (io.usethesource.vallang.IValue key : map) {
result[i++] = new RascalVariable(target, key.toString(), decl.isMap() ? decl.getValueType() : vt, map.get(key));
}
return result;
}
@Override
public IVariable[] visitNumber(Type type) {
return new IVariable[0];
}
@Override
public IVariable[] visitAlias(Type type) {
return type.getAliased().accept(this);
}
@Override
public IVariable[] visitSet(Type type) {
ISet set = (ISet) value;
IVariable[] result = new IVariable[set.size()];
int i = 0;
for (io.usethesource.vallang.IValue elem : set) {
result[i++] = new RascalVariable(target, "[" + i + "]", decl.isSet() ? decl.getElementType() : vt, elem);
}
return result;
}
@Override
public IVariable[] visitSourceLocation(Type type) {
return new IVariable[0];
}
@Override
public IVariable[] visitString(Type type) {
return new IVariable[0];
}
@Override
public IVariable[] visitNode(Type type) {
INode node = (INode) value;
IVariable[] result = new IVariable[node.arity()];
for (int i = 0; i < result.length; i++) {
result[i] = new RascalVariable(target, "[" + i + "]", TypeFactory.getInstance().valueType(), node.get(i));
}
return result;
}
@Override
public IVariable[] visitConstructor(Type type) {
if (type.isSubtypeOf(RascalValueFactory.Tree)) {
return visitTree();
}
IConstructor node = (IConstructor) value;
IVariable[] result = new IVariable[node.arity()];
for (int i = 0; i < result.length; i++) {
result[i] = new RascalVariable(target, type.hasFieldNames() ? type.getFieldName(i) : "" + i, node.getConstructorType().getFieldType(i), node.get(i));
}
return result;
}
private IVariable[] visitTree() {
ITree tree = (ITree) value;
if (TreeAdapter.isList(tree)) {
IList elems = TreeAdapter.getListASTArgs(tree);
IVariable[] vars = new IVariable[elems.length()];
int i = 0;
for (io.usethesource.vallang.IValue elem : elems) {
vars[i++] = new RascalVariable(target, "elem " + i, RascalTypeFactory.getInstance().nonTerminalType((IConstructor) elem), elem);
}
return vars;
}
if (TreeAdapter.isAppl(tree)) {
IConstructor prod = TreeAdapter.getProduction(tree);
boolean isLex = ProductionAdapter.isLexical(prod);
IList astSymbols = isLex ? ProductionAdapter.getSymbols(prod) : ProductionAdapter.getASTSymbols(prod);
IList args = isLex ? TreeAdapter.getArgs(tree) : TreeAdapter.getASTArgs(tree);
IVariable[] vars = new IVariable[args.length()];
for (int i = 0; i < vars.length; i++) {
IConstructor sym = (IConstructor) astSymbols.get(i);
String label = SymbolAdapter.isLabel(sym) ? SymbolAdapter.getLabelName(sym) : ("arg " + i);
vars[i] = new RascalVariable(target, label, RascalTypeFactory.getInstance().nonTerminalType(sym), args.get(i));
}
return vars;
}
if (TreeAdapter.isAmb(tree)) {
ISet alts = TreeAdapter.getAlternatives(tree);
IVariable[] vars = new IVariable[alts.size()];
int i = 0;
for (io.usethesource.vallang.IValue elem : alts) {
vars[i++] = new RascalVariable(target, "alt " + i, RascalTypeFactory.getInstance().nonTerminalType((IConstructor) elem) , elem);
}
return vars;
}
return new IVariable[0];
}
@Override
public IVariable[] visitAbstractData(Type type) {
return visitConstructor(((IConstructor) value).getConstructorType());
}
@Override
public IVariable[] visitTuple(Type type) {
ITuple node = (ITuple) value;
IVariable[] result = new IVariable[node.arity()];
for (int i = 0; i < result.length; i++) {
Type toUse = decl.isTuple() ? decl : type;
result[i] = new RascalVariable(target, toUse.hasFieldNames() ? toUse.getFieldName(i) : "[" + i + "]", toUse.getFieldType(i), node.get(i));
}
return result;
}
@Override
public IVariable[] visitValue(Type type) {
return new IVariable[0];
}
@Override
public IVariable[] visitVoid(Type type) {
return new IVariable[0];
}
@Override
public IVariable[] visitBool(Type boolType) {
return new IVariable[0];
}
@Override
public IVariable[] visitParameter(Type parameterType) {
return new IVariable[0];
}
@Override
public IVariable[] visitExternal(Type externalType) {
return new IVariable[0];
}
@Override
public IVariable[] visitDateTime(Type type) {
return new IVariable[0];
}
});
}
public boolean hasVariables() throws DebugException {
return false;
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IValue#hasVariables()
*/
public boolean hasVariables2() throws DebugException {
if (value == null) {
return false;
}
Type type = value.getType();
return type.isList() || type.isMap() || type.isSet() || type.isAliased() || type.isNode() || type.isConstructor() || type.isRelation();
}
/* (non-Javadoc)
* @see org.eclipse.debug.core.model.IValue#isAllocated()
*/
public boolean isAllocated() throws DebugException {
return true;
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
@SuppressWarnings("rawtypes")
@Override
public Object getAdapter(Class adapter) {
return target.getAdapter(adapter);
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
if (value != null)
return value.toString();
else
return "<uninitialized>";
}
public IValue getValue() {
return this;
}
}