package org.cloudsmith.geppetto.ruby.jruby;
import java.util.List;
import java.util.Map;
import org.jruby.ast.ArrayNode;
import org.jruby.ast.Colon2Node;
import org.jruby.ast.ConstNode;
import org.jruby.ast.HashNode;
import org.jruby.ast.Node;
import org.jruby.ast.SymbolNode;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
* Evaluates (a limited set of) Ruby constant expressions.
*
*/
public class ConstEvaluator extends AbstractJRubyVisitor {
public Object eval(Node node) {
return node.accept(this);
}
@SuppressWarnings("unchecked")
private List<String> stringList(Object x) {
if(x instanceof List)
return (List<String>)x; // have faith
if(x instanceof String)
return Lists.newArrayList((String)x);
throw new IllegalArgumentException("Not a string or lists of strings");
}
@Override
public Object visitArrayNode(ArrayNode iVisited) {
List<Object> result = Lists.newArrayList();
for(Node n : iVisited.childNodes())
result.add(eval(n));
return result;
}
@Override
public Object visitSymbolNode(SymbolNode iVisited) {
return iVisited.getName();
}
@Override
public Object visitHashNode(HashNode iVisited) {
Map<Object, Object> result = Maps.newHashMap();
List<Node> children = iVisited.childNodes();
children = children.get(0).childNodes();
for(int i = 0; i < children.size(); i++) {
Object key = eval(children.get(i++));
Object value = eval(children.get(i));
result.put(key, value);
}
return result;
}
@Override
public Object visitConstNode(ConstNode iVisited) {
return iVisited.getName();
}
@Override
public Object visitColon2Node(Colon2Node iVisited) {
return splice(eval(iVisited.getLeftNode()), iVisited.getName());
}
private List<String> splice(Object a, Object b) {
return addAll(stringList(a),stringList(b));
}
private List<String> addAll(List<String> a, List<String> b) {
a.addAll(b);
return a;
}
}