// Path: src/main/java/com/shapesecurity/shift/es2017/semantics/asg/Node.java
// public interface Node {
// 
// 	default boolean equalsIgnoringChildren(@Nonnull Node node) {
// 		return node.getClass() == this.getClass();
// 	}
// 
// }
// 
// Path: src/main/java/com/shapesecurity/shift/es2017/semantics/visitor/GetDescendents.java
// public final class GetDescendents extends MonoidalReducer<ConcatList<Node>> {
// 
// 	public static ImmutableList<Node> getDescendants(@Nonnull Node node) {
// 		return new Director<>(new GetDescendents()).reduceNode(node).toList();
// 	}
// 
// 	private GetDescendents() {
// 		super(new Monoid.ConcatListAppend<>());
// 	}
// 
// 	@Nonnull
// 	@Override
// 	public ConcatList<Node> reduceAll(@Nonnull Node node, @Nonnull ConcatList<Node> reduced) {
// 		return reduced.append1(node);
// 	}
// }


import com.shapesecurity.functional.data.ImmutableList;
import com.shapesecurity.shift.es2017.parser.Parser;
import com.shapesecurity.shift.es2017.semantics.asg.Node;
import com.shapesecurity.shift.es2017.semantics.visitor.GetDescendents;
import org.junit.Test;
import javax.annotation.Nonnull;
import java.nio.charset.StandardCharsets;
import java.util.IdentityHashMap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
		return nodes.mapWithIndex((nodeIndex, node) -> {
			Integer originalLocation = nodeOriginalLocation.get(node);
			if (originalLocation == null) {
				nodeOriginalLocation.put(node, nodeIndex);
				return nodeIndex;
			} else {
				return originalLocation;
			}
		});
	}

	@Test
	public void testCyclicGraph() throws Exception {
		String programText = "x: {\n" +
			"  break x;\n" +
			"  break x;\n" +
			"  break x;\n" +
			"  break x;\n" +
			"  break x;\n" +
			"  break x;\n" +
			"  break x;\n" +
			"  break x;\n" +
			"}\n" +
			"{\n" +
			"  many(); things();\n" +
			"}";
		Semantics asg = Explicator.deriveSemantics(Parser.parseScript(programText));
		ImmutableList<Node> asgNodes = GetDescendents.getDescendants(asg.node);

		Semantics asgRebuilt = Util.rebuildSemantics(asg);
// Path: src/main/java/com/shapesecurity/shift/es2017/semantics/asg/Node.java
// public interface Node {
// 
// 	default boolean equalsIgnoringChildren(@Nonnull Node node) {
// 		return node.getClass() == this.getClass();
// 	}
// 
// }
// 
// Path: src/main/java/com/shapesecurity/shift/es2017/semantics/visitor/GetDescendents.java
// public final class GetDescendents extends MonoidalReducer<ConcatList<Node>> {
// 
// 	public static ImmutableList<Node> getDescendants(@Nonnull Node node) {
// 		return new Director<>(new GetDescendents()).reduceNode(node).toList();
// 	}
// 
// 	private GetDescendents() {
// 		super(new Monoid.ConcatListAppend<>());
// 	}
// 
// 	@Nonnull
// 	@Override
// 	public ConcatList<Node> reduceAll(@Nonnull Node node, @Nonnull ConcatList<Node> reduced) {
// 		return reduced.append1(node);
// 	}
// }


// Path: src/test/java/com/shapesecurity/shift/es2017/semantics/GetDescendentsTest.java
import com.shapesecurity.functional.data.ImmutableList;
import com.shapesecurity.shift.es2017.parser.Parser;
import com.shapesecurity.shift.es2017.semantics.asg.Node;
import com.shapesecurity.shift.es2017.semantics.visitor.GetDescendents;
import org.junit.Test;
import javax.annotation.Nonnull;
import java.nio.charset.StandardCharsets;
import java.util.IdentityHashMap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;

		return nodes.mapWithIndex((nodeIndex, node) -> {
			Integer originalLocation = nodeOriginalLocation.get(node);
			if (originalLocation == null) {
				nodeOriginalLocation.put(node, nodeIndex);
				return nodeIndex;
			} else {
				return originalLocation;
			}
		});
	}

	@Test
	public void testCyclicGraph() throws Exception {
		String programText = "x: {\n" +
			"  break x;\n" +
			"  break x;\n" +
			"  break x;\n" +
			"  break x;\n" +
			"  break x;\n" +
			"  break x;\n" +
			"  break x;\n" +
			"  break x;\n" +
			"}\n" +
			"{\n" +
			"  many(); things();\n" +
			"}";
		Semantics asg = Explicator.deriveSemantics(Parser.parseScript(programText));
		ImmutableList<Node> asgNodes = GetDescendents.getDescendants(asg.node);

		Semantics asgRebuilt = Util.rebuildSemantics(asg);
		ImmutableList<Node> asgRebuiltNodes = GetDescendents.getDescendants(asgRebuilt.node);