public class Equality extends BinaryOperation {
	@Nonnull
	public final Operator operator;
	@Nonnull
	public final NodeWithValue left;
	@Nonnull
	public final NodeWithValue right;


	public Equality(@Nonnull Operator operator, @Nonnull NodeWithValue left, @Nonnull NodeWithValue right) {
		this.operator = operator;
		this.left = left;
		this.right = right;
	}

	@Override
	@Nonnull
	public NodeWithValue left() {
		return this.left;
	}

	@Override
	@Nonnull
	public NodeWithValue right() {
		return this.right;
	}

	public enum Operator implements BinaryOperator { // TODO could get by with as few as one of these
		Eq("=="),
		Neq("!="),
		StrictEq("==="),
		StrictNeq("!==");

		@Nonnull
		public final String name;

		Operator(@Nonnull String name) {
			this.name = name;
		}
	}
} public class FloatMath extends BinaryOperation {
	@Nonnull
	public final Operator operator;
	@Nonnull
	public final NodeWithValue left;
	@Nonnull
	public final NodeWithValue right;


	public FloatMath(@Nonnull Operator operator, @Nonnull NodeWithValue left, @Nonnull NodeWithValue right) {
		this.operator = operator;
		this.left = left;
		this.right = right;
	}

	@Override
	@Nonnull
	public NodeWithValue left() {
		return this.left;
	}

	@Override
	@Nonnull
	public NodeWithValue right() {
		return this.right;
	}

	public enum Operator implements BinaryOperator {
		Plus("+"),
		Minus("-"),
		Mul("*"),
		Div("/"),
		Rem("%"),
		Exp("**");

		@Nonnull
		public final String name;

		Operator(@Nonnull String name) {
			this.name = name;
		}
	}
} public class In extends BinaryOperation {
	@Nonnull
	public final NodeWithValue left;


	@Nonnull

	public final NodeWithValue right;

	@Override
	@Nonnull
	public NodeWithValue left() {
		return this.left;
	}

	@Override
	@Nonnull
	public NodeWithValue right() {
		return this.right;
	}

	public In(@Nonnull NodeWithValue left, @Nonnull NodeWithValue right) {
		this.left = left;
		this.right = right;
	}
} public class InstanceOf extends BinaryOperation {
	@Nonnull
	public final NodeWithValue left;


	@Nonnull
	public final NodeWithValue right;

	@Override
	@Nonnull
	public NodeWithValue left() {
		return this.left;
	}

	@Override
	@Nonnull
	public NodeWithValue right() {
		return this.right;
	}

	public InstanceOf(@Nonnull NodeWithValue left, @Nonnull NodeWithValue right) {
		this.left = left;
		this.right = right;
	}
} public class IntMath extends BinaryOperation {
	@Nonnull
	public final Operator operator;
	@Nonnull
	public final NodeWithValue left;
	@Nonnull
	public final NodeWithValue right;


	public IntMath(@Nonnull Operator operator, @Nonnull NodeWithValue left, @Nonnull NodeWithValue right) {
		this.operator = operator;
		this.left = left;
		this.right = right;
	}

	@Override
	@Nonnull
	public NodeWithValue left() {
		return this.left;
	}

	@Override
	@Nonnull
	public NodeWithValue right() {
		return this.right;
	}

	public enum Operator implements BinaryOperator {
		BitwiseAnd("&"),
		BitwiseOr("|"),
		BitwiseXor("^"),
		LeftShift("<<"),
		RightShift(">>"),
		UnsignedRightShift(">>>");

		@Nonnull
		public final String name;

		Operator(@Nonnull String name) {
			this.name = name;
		}
	}
} public class Logic extends BinaryOperation {
	@Nonnull
	public final Operator operator;
	@Nonnull
	public final NodeWithValue left;


	@Nonnull

	public final NodeWithValue right;

	public Logic(@Nonnull Operator operator, @Nonnull NodeWithValue left, @Nonnull NodeWithValue right) {
		this.operator = operator;
		this.left = left;
		this.right = right;
	}

	@Override
	@Nonnull
	public NodeWithValue left() {
		return this.left;
	}

	@Override
	@Nonnull
	public NodeWithValue right() {
		return this.right;
	}

	public enum Operator implements BinaryOperator {
		And("&&"),
		Or("||");

		@Nonnull
		public final String name;

		Operator(@Nonnull String name) {
			this.name = name;
		}
	}

} public class RelationalComparison extends BinaryOperation {
	@Nonnull
	public final Operator operator;
	@Nonnull
	public final NodeWithValue left;


	@Nonnull

	public final NodeWithValue right;

	public RelationalComparison(@Nonnull Operator operator, @Nonnull NodeWithValue left, @Nonnull NodeWithValue right) {
		this.operator = operator;
		this.left = left;
		this.right = right;
	}

	@Override
	@Nonnull
	public NodeWithValue left() {
		return this.left;
	}

	@Override
	@Nonnull
	public NodeWithValue right() {
		return this.right;
	}

	public enum Operator implements BinaryOperator {
		LessThan("<"),
		LessThanEqual("<="),
		GreaterThan(">"),
		GreaterThanEqual(">=");

		@Nonnull
		public final String name;

		Operator(@Nonnull String name) {
			this.name = name;
		}
	}
} public class BlockWithValue implements NodeWithValue {
	@Nonnull
	public Block head;
	@Nonnull
	public NodeWithValue result;


	public BlockWithValue(@Nonnull Block head, @Nonnull NodeWithValue result) {
		this.head = head;
		this.result = result;
	}

	public BlockWithValue(@Nonnull ImmutableList<Node> children, @Nonnull NodeWithValue result) {
		this.head = new Block(children);
		this.result = result;
	}
} public class Call implements NodeWithValue {
	@Nonnull
	public final NodeWithValue callee;


	@Nonnull
	public final ImmutableList<NodeWithValue> arguments;

	public Call(@Nonnull NodeWithValue callee, @Nonnull ImmutableList<NodeWithValue> arguments) {
		this.callee = callee;
		this.arguments = arguments;
	}
} public class DeleteGlobalProperty implements NodeWithValue {


	@Nonnull
	public final String which;

	public DeleteGlobalProperty(@Nonnull String which) {
		this.which = which;
	}

	@Override
	public boolean equalsIgnoringChildren(@Nonnull Node node) {
		return node instanceof DeleteGlobalProperty && this.which.equals(((DeleteGlobalProperty) node).which);
	}
} public class DeleteProperty implements NodeWithValue {


	@Nonnull
	public final NodeWithValue object;
	@Nonnull
	public final NodeWithValue fieldExpression;
	public final boolean strict;

	public DeleteProperty(@Nonnull NodeWithValue object, @Nonnull NodeWithValue fieldExpression, boolean strict) {
		this.object = object;
		this.fieldExpression = fieldExpression;
		this.strict = strict;
	}

	@Override
	public boolean equalsIgnoringChildren(@Nonnull Node node) {
		return node instanceof DeleteProperty && this.strict == ((DeleteProperty) node).strict;
	}
} public class GlobalReference implements NodeWithValue {


	@Nonnull
	public final String name;

	public GlobalReference(@Nonnull String name) {
		this.name = name;
	}

	@Override
	public boolean equalsIgnoringChildren(@Nonnull Node node) {
		return node instanceof GlobalReference && this.name.equals(((GlobalReference) node).name);
	}
} public class Halt implements NodeWithValue {
	@Nonnull
	public static final Halt INSTANCE = new Halt();


	private Halt() {
	}

} public class Keys implements NodeWithValue {


	@Nonnull
	public final NodeWithValue _object;

	public Keys(@Nonnull NodeWithValue object) {
		_object = object;
	}
} public class LiteralBoolean implements Literal {


	public final boolean value;

	public LiteralBoolean(boolean value) {
		this.value = value;
	}

	@Override
	public boolean equalsIgnoringChildren(@Nonnull Node node) {
		return node instanceof LiteralBoolean && this.value == ((LiteralBoolean) node).value;
	}
} public class LiteralEmptyArray implements Literal {
	@Nonnull
	public static final LiteralEmptyArray INSTANCE = new LiteralEmptyArray();


	private LiteralEmptyArray() {
	}
} public class LiteralEmptyObject implements Literal {
	@Nonnull
	public static final LiteralEmptyObject INSTANCE = new LiteralEmptyObject();


	private LiteralEmptyObject() {
	}
} public class LiteralFunction implements Literal {
	@Nonnull
	public final Maybe<Variable> name;
	@Nonnull
	public final Maybe<Variable> arguments;
	@Nonnull
	public final ImmutableList<Variable> parameters;
	@Nonnull
	public final ImmutableList<Variable> locals;


	@Nonnull
	public final ImmutableList<Variable> captured;
	@Nonnull
	public final Block body;
	@Nonnull
	public final boolean isStrict;

	public LiteralFunction(
		@Nonnull Maybe<Variable> name, @Nonnull Maybe<Variable> arguments, @Nonnull ImmutableList<Variable> parameters, @Nonnull ImmutableList<Variable> locals,
		@Nonnull ImmutableList<Variable> captured, @Nonnull Block body, boolean isStrict
	) {
		this.name = name;
		this.arguments = arguments;
		this.parameters = parameters;
		this.locals = locals;
		this.captured = captured;
		this.body = body;
		this.isStrict = isStrict;
	}

	@Override
	public boolean equalsIgnoringChildren(@Nonnull Node node) {
		return node instanceof LiteralFunction &&
			this.name.equals(((LiteralFunction) node).name) &&
			this.arguments.equals(((LiteralFunction) node).arguments) &&
			this.parameters.equals(((LiteralFunction) node).parameters) &&
			this.locals.equals(((LiteralFunction) node).locals) &&
			this.captured.equals(((LiteralFunction) node).captured) &&
			this.isStrict == ((LiteralFunction) node).isStrict;
	}
} public class LiteralInfinity implements Literal {
	@Nonnull
	public static final LiteralInfinity INSTANCE = new LiteralInfinity();


	private LiteralInfinity() {
	}
} public class LiteralNull implements Literal {
	@Nonnull
	public static final LiteralNull INSTANCE = new LiteralNull();


	private LiteralNull() {
	}

} public class LiteralNumber implements Node, Literal {


	public final double value;

	public LiteralNumber(double value) {
		this.value = value;
	}

	@Override
	public boolean equalsIgnoringChildren(@Nonnull Node node) {
		return node instanceof LiteralNumber && this.value == ((LiteralNumber) node).value;
	}
} public class LiteralRegExp implements Literal {
	@Nonnull
	public final String pattern;
	public final boolean global;
	public final boolean ignoreCase;
	public final boolean multiLine;
	public final boolean sticky;
	public final boolean unicode;


	public LiteralRegExp(@Nonnull String pattern, boolean global, boolean ignoreCase, boolean multiLine, boolean sticky, boolean unicode) {
		this.pattern = pattern;
		this.global = global;
		this.ignoreCase = ignoreCase;
		this.multiLine = multiLine;
		this.sticky = sticky;
		this.unicode = unicode;
	}

	@Override
	public boolean equalsIgnoringChildren(@Nonnull Node node) {
		return node instanceof LiteralRegExp &&
			this.pattern.equals(((LiteralRegExp) node).pattern) &&
			this.global == ((LiteralRegExp) node).global &&
			this.ignoreCase == ((LiteralRegExp) node).ignoreCase &&
			this.multiLine == ((LiteralRegExp) node).ignoreCase &&
			this.sticky == ((LiteralRegExp) node).sticky &&
			this.unicode == ((LiteralRegExp) node).unicode;
	}
} public class LiteralString implements Literal {
	@Nonnull
	public final String value;


	public LiteralString(@Nonnull String value) {
		this.value = value;
	}

	@Override
	public boolean equalsIgnoringChildren(@Nonnull Node node) {
		return node instanceof LiteralString && this.value.equals(((LiteralString) node).value);
	}
} public class LiteralSymbol implements Literal {
	@Nonnull
	public final String description;


	public LiteralSymbol(@Nonnull String description) {
		this.description = description;
	}

	@Override
	public boolean equalsIgnoringChildren(@Nonnull Node node) {
		return node instanceof LiteralSymbol && this.description.equals(((LiteralSymbol) node).description);
	}
} public class LiteralUndefined implements Literal {
	@Nonnull
	public static final LiteralUndefined INSTANCE = new LiteralUndefined();


	private LiteralUndefined() {
	}
} public class LocalReference implements NodeWithValue {
	@Nonnull
	public Variable variable;


	public LocalReference(@Nonnull Variable variable) {
		this.variable = variable;
	}

	@Override
	public boolean equalsIgnoringChildren(@Nonnull Node node) {
		return node.getClass() == LocalReference.class && this.variable.equals(((LocalReference) node).variable);
	}
} public class MemberAccess implements NodeWithValue {
	@Nonnull
	public final NodeWithValue object;


	@Nonnull
	public final NodeWithValue fieldExpression;

	public MemberAccess(@Nonnull NodeWithValue object, @Nonnull NodeWithValue fieldExpression) {
		this.object = object;
		this.fieldExpression = fieldExpression;
	}
} public class MemberAssignment implements NodeWithValue {
	@Nonnull
	public final NodeWithValue object;
	@Nonnull
	public final NodeWithValue fieldExpression;
	@Nonnull
	public final MemberAssignmentProperty.StaticValue property;
	public final boolean strict;


	public MemberAssignment(
		@Nonnull NodeWithValue object, @Nonnull NodeWithValue fieldExpression,
		@Nonnull MemberAssignmentProperty.StaticValue property,
		boolean strict
	) {
		this.object = object;
		this.fieldExpression = fieldExpression;
		this.property = property;
		this.strict = strict;
	}

	public MemberAssignment(
		@Nonnull NodeWithValue object, @Nonnull NodeWithValue fieldExpression, @Nonnull NodeWithValue staticValue, boolean strict
	) {
		this.object = object;
		this.fieldExpression = fieldExpression;
		this.property = new MemberAssignmentProperty.StaticValue(staticValue);
		this.strict = strict;
	}

	@Override
	public boolean equalsIgnoringChildren(@Nonnull Node node) {
		return node instanceof MemberAssignment && this.strict == ((MemberAssignment) node).strict;
	}
} public class New implements NodeWithValue {
	@Nonnull
	public final NodeWithValue callee;
	@Nonnull
	public final ImmutableList<NodeWithValue> arguments;


	public New(@Nonnull NodeWithValue callee, @Nonnull ImmutableList<NodeWithValue> arguments) {
		this.callee = callee;
		this.arguments = arguments;
	}
} public class RequireObjectCoercible implements NodeWithValue {
	@Nonnull
	public final NodeWithValue expression;


	public RequireObjectCoercible(@Nonnull NodeWithValue expression) {
		this.expression = expression;
	}
} public class TemporaryReference extends LocalReference {
	public TemporaryReference() {
		super(new Variable(
			"LOCAL",
			ImmutableList.empty(),
			ImmutableList.empty()
		)); // TODO consider if this is what we actually want to do
	}

	// This is used in ReconstructingReducer
	public TemporaryReference(@Nonnull Variable variable) {
		super(variable);
	}
} public class This implements NodeWithValue {
	public final boolean strict;


	public This(boolean strict) {
		this.strict = strict;
	}

	@Override
	public boolean equalsIgnoringChildren(@Nonnull Node node) {
		return node instanceof This && this.strict == ((This) node).strict;
	}
} public class TypeCoercionNumber implements NodeWithValue {
	@Nonnull
	public final NodeWithValue expression;


	public TypeCoercionNumber(@Nonnull NodeWithValue expression) {
		this.expression = expression;
	}
} public class TypeCoercionString implements NodeWithValue {
	@Nonnull
	public final NodeWithValue expression;


	public TypeCoercionString(@Nonnull NodeWithValue expression) {
		this.expression = expression;
	}
} public class TypeofGlobal implements NodeWithValue {
	@Nonnull
	public final String which;


	public TypeofGlobal(@Nonnull String which) {
		this.which = which;
	}

	@Override
	public boolean equalsIgnoringChildren(@Nonnull Node node) {
		return node instanceof TypeofGlobal && this.which.equals(((TypeofGlobal) node).which);
	}
} public class BitwiseNot extends UnaryOperation {
	@Nonnull
	public final NodeWithValue expression;

	@Override
	@Nonnull
	public NodeWithValue expression() {
		return expression;
	}


	public BitwiseNot(@Nonnull NodeWithValue expression) {
		this.expression = expression;
	}
} public class Negation extends UnaryOperation {


	@Nonnull
	public final NodeWithValue expression;

	@Nonnull
	public NodeWithValue expression() {
		return this.expression;
	}

	public Negation(@Nonnull NodeWithValue expression) {
		this.expression = expression;
	}
} public class Not extends UnaryOperation {


	@Nonnull
	public final NodeWithValue expression;

	@Nonnull
	public NodeWithValue expression() {
		return this.expression;
	}

	public Not(@Nonnull NodeWithValue expression) {
		this.expression = expression;
	}
} public class Typeof extends UnaryOperation {
	@Nonnull
	public final NodeWithValue expression;

	@Nonnull
	public NodeWithValue expression() {
		return this.expression;
	}


	public Typeof(@Nonnull NodeWithValue expression) {
		this.expression = expression;
	}
} public class VoidOp extends UnaryOperation {


	@Nonnull
	public final NodeWithValue expression;

	@Nonnull
	public NodeWithValue expression() {
		return this.expression;
	}

	public VoidOp(@Nonnull NodeWithValue expression) {
		this.expression = expression;
	}
} public class VariableAssignment implements NodeWithValue {


	@Nonnull
	public final Either<GlobalReference, LocalReference> ref;
	@Nonnull
	public final NodeWithValue value;
	public final boolean strict;

	public VariableAssignment(
		@Nonnull Either<GlobalReference, LocalReference> ref, @Nonnull NodeWithValue value, boolean strict
	) {
		this.ref = ref;
		this.value = value;
		this.strict = strict;
	}

	public VariableAssignment(@Nonnull GlobalReference ref, @Nonnull NodeWithValue value, boolean strict) {
		this.ref = Either.left(ref);
		this.value = value;
		this.strict = strict;
	}

	public VariableAssignment(@Nonnull LocalReference ref, @Nonnull NodeWithValue value, boolean strict) {
		this.ref = Either.right(ref);
		this.value = value;
		this.strict = strict;
	}

	@Override
	public boolean equalsIgnoringChildren(@Nonnull Node node) {
		return node instanceof VariableAssignment && this.strict == ((VariableAssignment) node).strict;
	}
}
import com.shapesecurity.shift.es2017.semantics.asg.BinaryOperation.Equality;
import com.shapesecurity.shift.es2017.semantics.asg.BinaryOperation.FloatMath;
import com.shapesecurity.shift.es2017.semantics.asg.BinaryOperation.In;
import com.shapesecurity.shift.es2017.semantics.asg.BinaryOperation.InstanceOf;
import com.shapesecurity.shift.es2017.semantics.asg.BinaryOperation.IntMath;
import com.shapesecurity.shift.es2017.semantics.asg.BinaryOperation.Logic;
import com.shapesecurity.shift.es2017.semantics.asg.BinaryOperation.RelationalComparison;
import com.shapesecurity.shift.es2017.semantics.asg.BlockWithValue;
import com.shapesecurity.shift.es2017.semantics.asg.Call;
import com.shapesecurity.shift.es2017.semantics.asg.DeleteGlobalProperty;
import com.shapesecurity.shift.es2017.semantics.asg.DeleteProperty;
import com.shapesecurity.shift.es2017.semantics.asg.GlobalReference;
import com.shapesecurity.shift.es2017.semantics.asg.Halt;
import com.shapesecurity.shift.es2017.semantics.asg.Keys;
import com.shapesecurity.shift.es2017.semantics.asg.LiteralBoolean;
import com.shapesecurity.shift.es2017.semantics.asg.LiteralEmptyArray;
import com.shapesecurity.shift.es2017.semantics.asg.LiteralEmptyObject;
import com.shapesecurity.shift.es2017.semantics.asg.LiteralFunction;
import com.shapesecurity.shift.es2017.semantics.asg.LiteralInfinity;
import com.shapesecurity.shift.es2017.semantics.asg.LiteralNull;
import com.shapesecurity.shift.es2017.semantics.asg.LiteralNumber;
import com.shapesecurity.shift.es2017.semantics.asg.LiteralRegExp;
import com.shapesecurity.shift.es2017.semantics.asg.LiteralString;
import com.shapesecurity.shift.es2017.semantics.asg.LiteralSymbol;
import com.shapesecurity.shift.es2017.semantics.asg.LiteralUndefined;
import com.shapesecurity.shift.es2017.semantics.asg.LocalReference;
import com.shapesecurity.shift.es2017.semantics.asg.MemberAccess;
import com.shapesecurity.shift.es2017.semantics.asg.MemberAssignment;
import com.shapesecurity.shift.es2017.semantics.asg.New;
import com.shapesecurity.shift.es2017.semantics.asg.RequireObjectCoercible;
import com.shapesecurity.shift.es2017.semantics.asg.TemporaryReference;
import com.shapesecurity.shift.es2017.semantics.asg.This;
import com.shapesecurity.shift.es2017.semantics.asg.TypeCoercionNumber;
import com.shapesecurity.shift.es2017.semantics.asg.TypeCoercionString;
import com.shapesecurity.shift.es2017.semantics.asg.TypeofGlobal;
import com.shapesecurity.shift.es2017.semantics.asg.UnaryOperation.BitwiseNot;
import com.shapesecurity.shift.es2017.semantics.asg.UnaryOperation.Negation;
import com.shapesecurity.shift.es2017.semantics.asg.UnaryOperation.Not;
import com.shapesecurity.shift.es2017.semantics.asg.UnaryOperation.Typeof;
import com.shapesecurity.shift.es2017.semantics.asg.UnaryOperation.VoidOp;
import com.shapesecurity.shift.es2017.semantics.asg.VariableAssignment;
import javax.annotation.Nonnull;
package com.shapesecurity.shift.es2017.semantics.visitor;



public interface FAlgebraNodeWithValue<T> {
	@Nonnull
	T apply(BlockWithValue blockWithValue);

	@Nonnull
	T apply(Call call);

	@Nonnull
	T apply(DeleteGlobalProperty deleteGlobalProperty);

	@Nonnull
	T apply(DeleteProperty deleteProperty);

	@Nonnull
	T apply(GlobalReference globalReference);

	@Nonnull
	T apply(Halt halt);

	@Nonnull
	T apply(Keys keys);

	@Nonnull
	T apply(LiteralBoolean literalBoolean);

	@Nonnull
	T apply(LiteralEmptyArray literalEmptyArray);

	@Nonnull
	T apply(LiteralEmptyObject literalEmptyObject);

	@Nonnull
	T apply(LiteralFunction literalFunction);

	@Nonnull
	T apply(LiteralInfinity literalInfinity);

	@Nonnull
	T apply(LiteralNull literalNull);

	@Nonnull
	T apply(LiteralNumber literalNumber);

	@Nonnull
	T apply(LiteralRegExp literalRegExp);

	@Nonnull
	T apply(LiteralString literalString);

	@Nonnull
	T apply(LiteralSymbol literalSymbol);