// Copyright 2007-2009 Russ Cox.  All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include "re1.5.h"

static int
recursive(char *pc, const char *sp, Subject *input, const char **subp, int nsubp)
{
	const char *old;
	int off;

	if(inst_is_consumer(*pc)) {
		// If we need to match a character, but there's none left, it's fail
		if(sp >= input->end)
			return 0;
	}

	re1_5_stack_chk();

	switch(*pc++) {
	case Char:
		if(*sp != *pc++)
			return 0;
	case Any:
		return recursive(pc, sp+1, input, subp, nsubp);
	case Class:
	case ClassNot:
		if (!_re1_5_classmatch(pc, sp))
			return 0;
		pc += *(unsigned char*)pc * 2 + 1;
		return recursive(pc, sp+1, input, subp, nsubp);
	case NamedClass:
		if (!_re1_5_namedclassmatch(pc, sp))
			return 0;
		return recursive(pc+1, sp+1, input, subp, nsubp);
	case Match:
		return 1;
	case Jmp:
		off = (signed char)*pc++;
		return recursive(pc + off, sp, input, subp, nsubp);
	case Split:
		off = (signed char)*pc++;
		if(recursive(pc, sp, input, subp, nsubp))
			return 1;
		return recursive(pc + off, sp, input, subp, nsubp);
	case RSplit:
		off = (signed char)*pc++;
		if(recursive(pc + off, sp, input, subp, nsubp))
			return 1;
		return recursive(pc, sp, input, subp, nsubp);
	case Save:
		off = (unsigned char)*pc++;
		if(off >= nsubp)
			return recursive(pc, sp, input, subp, nsubp);
		old = subp[off];
		subp[off] = sp;
		if(recursive(pc, sp, input, subp, nsubp))
			return 1;
		subp[off] = old;
		return 0;
	case Bol:
		if(sp != input->begin)
			return 0;
		return recursive(pc, sp, input, subp, nsubp);
	case Eol:
		if(sp != input->end)
			return 0;
		return recursive(pc, sp, input, subp, nsubp);
	}
	re1_5_fatal("recursive");
	return -1;
}

int
re1_5_recursiveprog(ByteProg *prog, Subject *input, const char **subp, int nsubp, int is_anchored)
{
	return recursive(HANDLE_ANCHORED(prog->insts, is_anchored), input->begin, input, subp, nsubp);
}