
class Prolog::LREP::Message {
	use IO::String;
	has $.context is rw;
	has $.input is rw = "";
	has IO::String $.output is rw = IO::String.new;
}

class Prolog::LREP {

	use MONKEY-SEE-NO-EVAL;
	use Linenoise;
	use Prolog::Grammar;
	use Prolog::Actions;
	
	has $.context is rw;
	has $.composed is rw;
	
	# Insane self-replacing func that keeps nesting the scope with each eval,
	# thereby allowing you to create lexical vars
	our &f;
	sub context-eval($code, $context) {
		my $result;
		&Prolog::LREP::f ||= -> $c { EVAL($c, context => $context) };
		&Prolog::LREP::f('&Prolog::LREP::f = -> $c { use MONKEY-SEE-NO-EVAL; EVAL($c) }; ' ~ $code);
	}
	
	sub read_middleware(&handler) {
		-> $message {
			my $cmd = linenoise '> ';
			last if !$cmd.defined;
		}
	}
	
	method add_middleware(*@middleware) {
		$.composed ||= -> $message { $message };
		for @middleware -> $mid {
			$.composed = $mid($.composed);
		}
	}
	
	method start {
		self.add_middleware(&read_middleware);
		loop {
			my $blank_message =
				Prolog::LREP::Message.new(context => $.context);
			&($.composed)($blank_message);
		}
	}
	
	our sub here {
		my $context = CALLER::;
		my $repl = Prolog::LREP.new(context => $context);
		$repl.start;
	}
}

