// Path: src/main/java/com/github/kmizu/jcombinator/datatype/Tuple2.java
// public class Tuple2<X, Y> {
//     private X item1;
//     private Y item2;
// 
//     public Tuple2(X item1, Y item2) {
//         this.item1 = item1;
//         this.item2 = item2;
//     }
// 
//     public X item1() {
//         return item1;
//     }
// 
//     public Y item2() {
//         return item2;
//     }
// 
//     public <U> U extract(Function2<X, Y, U> f) {
//         return f.invoke(item1, item2);
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
// 
//         Tuple2<?, ?> tp2 = (Tuple2<?, ?>) o;
// 
//         if (!item1.equals(tp2.item1)) return false;
//         return item2.equals(tp2.item2);
//     }
// 
//     @Override
//     public int hashCode() {
//         int result = item1.hashCode();
//         result = 31 * result + item2.hashCode();
//         return result;
//     }
// 
//     @Override
//     public String toString() {
//         return "Tuple2{" + "item1=" + item1 + ", item2=" + item2 + '}';
//     }
// }


import com.github.kmizu.jcombinator.datatype.Tuple2;
package com.github.kmizu.jcombinator;


/**
 * This parser matches concatenation like `lhs rhs`
 * @param <X> The first element type of `Tuple2`
 * @param <Y> The second element type of `Tuple2`
 */
public class Cat<X, Y> implements Parser<Tuple2<X, Y>> {
	private Parser<X> lhs;
	private Parser<Y> rhs;
	public Cat(Parser<X> lhs, Parser<Y> rhs) {
		this.lhs = lhs;
		this.rhs = rhs;
	}
	public Parser<X> getLhs() {
		return lhs;
	}
	
	public Parser<Y> getRhs() {
		return rhs;
	}
	
	@Override
	public ParseResult<Tuple2<X, Y>> invoke(String input) {
		ParseResult<X> lresult = lhs.invoke(input);
		return lresult.fold(
		  (succ1) -> {			  
			  ParseResult<Y> rresult = rhs.invoke(succ1.next());
			  return rresult.fold(
			    (succ2) -> new ParseResult.Success<>(new Tuple2<>(succ1.value(), succ2.value()), succ2.next()),
			    (failure) -> {
// Path: src/main/java/com/github/kmizu/jcombinator/datatype/Tuple2.java
// public class Tuple2<X, Y> {
//     private X item1;
//     private Y item2;
// 
//     public Tuple2(X item1, Y item2) {
//         this.item1 = item1;
//         this.item2 = item2;
//     }
// 
//     public X item1() {
//         return item1;
//     }
// 
//     public Y item2() {
//         return item2;
//     }
// 
//     public <U> U extract(Function2<X, Y, U> f) {
//         return f.invoke(item1, item2);
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
// 
//         Tuple2<?, ?> tp2 = (Tuple2<?, ?>) o;
// 
//         if (!item1.equals(tp2.item1)) return false;
//         return item2.equals(tp2.item2);
//     }
// 
//     @Override
//     public int hashCode() {
//         int result = item1.hashCode();
//         result = 31 * result + item2.hashCode();
//         return result;
//     }
// 
//     @Override
//     public String toString() {
//         return "Tuple2{" + "item1=" + item1 + ", item2=" + item2 + '}';
//     }
// }


// Path: src/main/java/com/github/kmizu/jcombinator/Cat.java
import com.github.kmizu.jcombinator.datatype.Tuple2;

package com.github.kmizu.jcombinator;


/**
 * This parser matches concatenation like `lhs rhs`
 * @param <X> The first element type of `Tuple2`
 * @param <Y> The second element type of `Tuple2`
 */
public class Cat<X, Y> implements Parser<Tuple2<X, Y>> {
	private Parser<X> lhs;
	private Parser<Y> rhs;
	public Cat(Parser<X> lhs, Parser<Y> rhs) {
		this.lhs = lhs;
		this.rhs = rhs;
	}
	public Parser<X> getLhs() {
		return lhs;
	}
	
	public Parser<Y> getRhs() {
		return rhs;
	}
	
	@Override
	public ParseResult<Tuple2<X, Y>> invoke(String input) {
		ParseResult<X> lresult = lhs.invoke(input);
		return lresult.fold(
		  (succ1) -> {			  
			  ParseResult<Y> rresult = rhs.invoke(succ1.next());
			  return rresult.fold(
			    (succ2) -> new ParseResult.Success<>(new Tuple2<>(succ1.value(), succ2.value()), succ2.next()),
			    (failure) -> {
			    	ParseResult<Tuple2<X, Y>> newFailure = new ParseResult.Failure<>(failure.message(), failure.next());