blob: 8d4636d0df20198a028ef5af87bf4c81444aaedf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015, 2016 Red Hat, Inc.
* 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:
* Red Hat Inc. - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.wst.jsdt.internal.esprima;
import java.util.Map;
import java.util.Stack;
import org.eclipse.core.runtime.Assert;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
/**
* @author Gorkem Ercan
* @since 2.0
*/
public class EStreeVisitor {
public enum VisitOptions{
/**
* Traverse children
*/
CONTINUE,
/**
* Skip children
*/
SKIP,
/**
* Break traversal
*/
BREAK }
class WorkElement{
ScriptObjectMirror node;
boolean endVisit;
String key;
/**
*
*/
public WorkElement(ScriptObjectMirror node,String key, boolean endVisit) {
this.node = node;
this.key = key;
this.endVisit = endVisit;
}
}
final private Stack<WorkElement> workStack = new Stack<WorkElement>();
public void traverse(ScriptObjectMirror root) {
workStack.push(new WorkElement(root,null, false));
while (!workStack.empty()) {
WorkElement element = workStack.pop();
VisitOptions vo = callVisit(element);
if (vo == VisitOptions.BREAK) {
return;
}
// No breaks push endVisit to stack
if (!element.endVisit)
workStack.push(new WorkElement(element.node, element.key, true));
if (element.endVisit || vo == VisitOptions.SKIP) { // skip children
continue;
}
// Find children and add them to worklist
ESTreeNodeTypes nodeType = getNodeType(element);
Assert.isNotNull(nodeType);
String[] keys = nodeType.getVisitorKeys();
for (int i = keys.length - 1; i > -1; i--) {
Object o = element.node.getMember(keys[i]);
if (o instanceof ScriptObjectMirror) {
ScriptObjectMirror candidate = (ScriptObjectMirror) o;
if (candidate.isArray()) {
// Create WorkElements for Array in reverse order
// to keep the order coming out of stack
Object[] arrayElements = candidate.entrySet().toArray();
for (int j = arrayElements.length-1; j > -1; j--) {
Map.Entry<String, Object> entry = (java.util.Map.Entry<String, Object>) arrayElements[j];
Object result = entry.getValue();
if (result instanceof ScriptObjectMirror) {
workStack.push(new WorkElement((ScriptObjectMirror) result, keys[i] ,false));
}
}
}
else {
workStack.push(new WorkElement(candidate, keys[i], false));
}
}
}
}
}
private VisitOptions callVisit(WorkElement element){
ESTreeNodeTypes nodeType = getNodeType(element);
Assert.isNotNull(nodeType);
if(element.endVisit){
return endVisit(element.node, nodeType, element.key);
}
return visit(element.node, nodeType, element.key);
}
private ESTreeNodeTypes getNodeType(WorkElement element) {
String type = (String)element.node.get("type");
ESTreeNodeTypes nodeType = ESTreeNodeTypes.valueOf(type);
return nodeType;
}
public VisitOptions visit(ScriptObjectMirror object, ESTreeNodeTypes nodeType, String key){
return VisitOptions.CONTINUE;
}
public VisitOptions endVisit(ScriptObjectMirror object, ESTreeNodeTypes nodeType, String key){
return VisitOptions.CONTINUE;
}
}