// 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;
package com.shapesecurity.shift.es2017.semantics;




public class GetDescendentsTest {

	// copied from JDK 10 java.lang.StringLatin1 to ensure consistency across JVM implementations
	private static int hashCode(byte[] value) {
		int h = 0;
		for (byte v : value) {
			h = 31 * h + (v & 0xff);
		}
		return h;
	}

	@Test
	public void testVisitor() throws Exception {
		String programText = "var z; typeof a; eval; ({ set a(b) { a = 0; }, get a(){} }).a = 0; " +
			"(function() { 'use strict'; try { undefined = 0; } catch (e) {} })(); " +
			"({a: 1}).a+(-1)+1-1*1/1%1|1&1^1<<1>>>1>>1; b = 1<1>1<=1>=1==1===1!=1!==!1;" +
			"b++; b in {}; f = (function (a) { return typeof 1;});" +
			"f(); f(1); f(1, []); f(1, [], null); f(1, [], null, this); f(1, [], null, this, /a/g); new f;" +
			"delete b; if (true) delete { a: 1}.a; if (false) ; else a = ~1; try { throw 'err'; } catch (e) {};" +
			"a instanceof Number; a = 2e308; a = 1.1; o = {}; (function() { 'use strict'; f(this); o.a = 1; delete o.a; })();" +
			"a = {'a':1}; for (b in a) ;" +
			"i = 1, j = 1; switch(i) { case --j: break; }" +
			"(function(a){arguments = {0:'a', 1:'b'}; arguments[0]=1; c = arguments[0]})(2);" +
			"(function A() { \n" +
			"  try { a = 1; return a;} catch(e) { a = 5; } finally { a = 2;}\n" +
			"})();" +
			"(function A() { \n" +
			"  label: try { } finally { break label; }; return 0;\n" +
			"})();";

		Semantics asg = Explicator.deriveSemantics(Parser.parseScript(programText));
// 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;

package com.shapesecurity.shift.es2017.semantics;




public class GetDescendentsTest {

	// copied from JDK 10 java.lang.StringLatin1 to ensure consistency across JVM implementations
	private static int hashCode(byte[] value) {
		int h = 0;
		for (byte v : value) {
			h = 31 * h + (v & 0xff);
		}
		return h;
	}

	@Test
	public void testVisitor() throws Exception {
		String programText = "var z; typeof a; eval; ({ set a(b) { a = 0; }, get a(){} }).a = 0; " +
			"(function() { 'use strict'; try { undefined = 0; } catch (e) {} })(); " +
			"({a: 1}).a+(-1)+1-1*1/1%1|1&1^1<<1>>>1>>1; b = 1<1>1<=1>=1==1===1!=1!==!1;" +
			"b++; b in {}; f = (function (a) { return typeof 1;});" +
			"f(); f(1); f(1, []); f(1, [], null); f(1, [], null, this); f(1, [], null, this, /a/g); new f;" +
			"delete b; if (true) delete { a: 1}.a; if (false) ; else a = ~1; try { throw 'err'; } catch (e) {};" +
			"a instanceof Number; a = 2e308; a = 1.1; o = {}; (function() { 'use strict'; f(this); o.a = 1; delete o.a; })();" +
			"a = {'a':1}; for (b in a) ;" +
			"i = 1, j = 1; switch(i) { case --j: break; }" +
			"(function(a){arguments = {0:'a', 1:'b'}; arguments[0]=1; c = arguments[0]})(2);" +
			"(function A() { \n" +
			"  try { a = 1; return a;} catch(e) { a = 5; } finally { a = 2;}\n" +
			"})();" +
			"(function A() { \n" +
			"  label: try { } finally { break label; }; return 0;\n" +
			"})();";

		Semantics asg = Explicator.deriveSemantics(Parser.parseScript(programText));
		ImmutableList<Node> nodes = GetDescendents.getDescendants(asg.node);