// Path: src/main/java/com/github/kmizu/jcombinator/ParseResult.java
// public interface ParseResult<T> {
// 	public static class Success<T> implements ParseResult<T> {
// 		private T value;
// 		private String next;
// 		Success(T value, String next) {
// 			this.value = value;
// 			this.next = next;
// 		}
// 		public T value() {
// 			return value;
// 		}
// 		public String next() {
// 			return next;
// 		}
// 		
// 		@Override
// 		public <U> U fold(
// 		  Function1<Success<T>, U> succ,
// 		  Function1<Failure<T>, U> fail) {
// 			return succ.invoke(this);
// 		}
// 	
// 		@Override
// 		public void fold(
// 			Procedure1<Success<T>> succ,
// 			Procedure1<Failure<T>> fail
// 		) {
// 			succ.invoke(this);
// 		}
// 
// 		@Override
// 		public <U> ParseResult<U> map(Function1<T, U> fn) {
// 			return new Success<U>(fn.invoke(value), next);
// 		}
// 
// 		@Override
// 		public void onSuccess(Procedure1<Success<T>> succ) {
// 			succ.invoke(this);
// 		}
// 	}
// 	
// 	public static class Failure<T> implements ParseResult<T> {		
// 		private String message;
// 		private String next;
// 		public Failure(String message, String next) {
// 			this.message = message;
// 			this.next = next;
// 		}
// 		public String message() {
// 			return message;
// 		}
// 		public String next() {
// 			return next;
// 		}
// 		
// 		@Override
// 		public <U> U fold(
// 		  Function1<Success<T>, U> succ,
// 		  Function1<Failure<T>, U> fail) {
// 			return fail.invoke(this);
// 		}
// 		
// 		@Override
// 		public void fold(
// 			Procedure1<Success<T>> succ,
// 			Procedure1<Failure<T>> fail
// 		) {
// 			fail.invoke(this);
// 		}
// 
// 		@Override
// 		public <U> ParseResult<U> map(Function1<T, U> fn) {
// 			return (ParseResult<U>)this;
// 		}
// 	    
// 		@Override
// 		public void onSuccess(Procedure1<Success<T>> succ) {
// 			
// 		}
// 	}
// 	
// 	<U> U fold(
// 		Function1<Success<T>, U> succ,
// 	    Function1<Failure<T>, U> fail
// 	);
// 	
// 	void fold(
// 		Procedure1<Success<T>> succ,
// 		Procedure1<Failure<T>> fail
// 	);
// 	
// 	void onSuccess(Procedure1<Success<T>> succ);
// 
// 	<U> ParseResult<U> map(Function1<T, U> fn);
// }
// 
// Path: src/main/java/com/github/kmizu/jcombinator/datatype/Function0.java
// public interface Function0<R> {
//     R invoke();
// }
// 
// Path: src/main/java/com/github/kmizu/jcombinator/datatype/Function1.java
// public interface Function1<T1, R> {
//     R invoke(T1 arg);
// }


import com.github.kmizu.jcombinator.ParseResult;
import com.github.kmizu.jcombinator.datatype.Function0;
import com.github.kmizu.jcombinator.datatype.Function1;
        public Boolean visitRSequence(AstNode.RSequence node, SuccessfullContinuation context) {
            return node.getLhs().accept(this, () ->
                node.getRhs().accept(this, context)
            );
        }

        @Override
        public Boolean visitRRepeat0(AstNode.RRepeat0 node, SuccessfullContinuation context) {
            Function1<Function0<Boolean>, Boolean>[] onSuccessRep = new Function1[1];
            onSuccessRep[0] = (f) -> {
                final int start = cursor;
                final SuccessfullContinuation nf = () -> {
                    cursor = start;
                    return context.invoke() ? true : f.invoke();
                };
                return (node.getTarget().accept(
                    this,
                    () -> onSuccessRep[0].invoke(nf)
                ) ? true : nf.invoke());
            };
            return onSuccessRep[0].invoke(context);
        }

        @Override
        public Boolean visitRRepeat1(AstNode.RRepeat1 node, SuccessfullContinuation context) {
            throw new UnsupportedOperationException("ExpressionInterpreter#visit(AstNode.RRepeat1, SuccessfullContinuation)");
        }
    }

    public boolean matches(String regex, String input) {
// Path: src/main/java/com/github/kmizu/jcombinator/ParseResult.java
// public interface ParseResult<T> {
// 	public static class Success<T> implements ParseResult<T> {
// 		private T value;
// 		private String next;
// 		Success(T value, String next) {
// 			this.value = value;
// 			this.next = next;
// 		}
// 		public T value() {
// 			return value;
// 		}
// 		public String next() {
// 			return next;
// 		}
// 		
// 		@Override
// 		public <U> U fold(
// 		  Function1<Success<T>, U> succ,
// 		  Function1<Failure<T>, U> fail) {
// 			return succ.invoke(this);
// 		}
// 	
// 		@Override
// 		public void fold(
// 			Procedure1<Success<T>> succ,
// 			Procedure1<Failure<T>> fail
// 		) {
// 			succ.invoke(this);
// 		}
// 
// 		@Override
// 		public <U> ParseResult<U> map(Function1<T, U> fn) {
// 			return new Success<U>(fn.invoke(value), next);
// 		}
// 
// 		@Override
// 		public void onSuccess(Procedure1<Success<T>> succ) {
// 			succ.invoke(this);
// 		}
// 	}
// 	
// 	public static class Failure<T> implements ParseResult<T> {		
// 		private String message;
// 		private String next;
// 		public Failure(String message, String next) {
// 			this.message = message;
// 			this.next = next;
// 		}
// 		public String message() {
// 			return message;
// 		}
// 		public String next() {
// 			return next;
// 		}
// 		
// 		@Override
// 		public <U> U fold(
// 		  Function1<Success<T>, U> succ,
// 		  Function1<Failure<T>, U> fail) {
// 			return fail.invoke(this);
// 		}
// 		
// 		@Override
// 		public void fold(
// 			Procedure1<Success<T>> succ,
// 			Procedure1<Failure<T>> fail
// 		) {
// 			fail.invoke(this);
// 		}
// 
// 		@Override
// 		public <U> ParseResult<U> map(Function1<T, U> fn) {
// 			return (ParseResult<U>)this;
// 		}
// 	    
// 		@Override
// 		public void onSuccess(Procedure1<Success<T>> succ) {
// 			
// 		}
// 	}
// 	
// 	<U> U fold(
// 		Function1<Success<T>, U> succ,
// 	    Function1<Failure<T>, U> fail
// 	);
// 	
// 	void fold(
// 		Procedure1<Success<T>> succ,
// 		Procedure1<Failure<T>> fail
// 	);
// 	
// 	void onSuccess(Procedure1<Success<T>> succ);
// 
// 	<U> ParseResult<U> map(Function1<T, U> fn);
// }
// 
// Path: src/main/java/com/github/kmizu/jcombinator/datatype/Function0.java
// public interface Function0<R> {
//     R invoke();
// }
// 
// Path: src/main/java/com/github/kmizu/jcombinator/datatype/Function1.java
// public interface Function1<T1, R> {
//     R invoke(T1 arg);
// }


// Path: src/main/java/com/github/kmizu/jcombinator/showcase/regex/RegexInterpreter.java
import com.github.kmizu.jcombinator.ParseResult;
import com.github.kmizu.jcombinator.datatype.Function0;
import com.github.kmizu.jcombinator.datatype.Function1;

        public Boolean visitRSequence(AstNode.RSequence node, SuccessfullContinuation context) {
            return node.getLhs().accept(this, () ->
                node.getRhs().accept(this, context)
            );
        }

        @Override
        public Boolean visitRRepeat0(AstNode.RRepeat0 node, SuccessfullContinuation context) {
            Function1<Function0<Boolean>, Boolean>[] onSuccessRep = new Function1[1];
            onSuccessRep[0] = (f) -> {
                final int start = cursor;
                final SuccessfullContinuation nf = () -> {
                    cursor = start;
                    return context.invoke() ? true : f.invoke();
                };
                return (node.getTarget().accept(
                    this,
                    () -> onSuccessRep[0].invoke(nf)
                ) ? true : nf.invoke());
            };
            return onSuccessRep[0].invoke(context);
        }

        @Override
        public Boolean visitRRepeat1(AstNode.RRepeat1 node, SuccessfullContinuation context) {
            throw new UnsupportedOperationException("ExpressionInterpreter#visit(AstNode.RRepeat1, SuccessfullContinuation)");
        }
    }

    public boolean matches(String regex, String input) {
        ParseResult<AstNode.RExpression> result = new RegexParser().expression().invoke(regex);