//Реализует язык перечисления номеров, расширенный исключениями

function parseEnum(code, varname){
//Синтаксис языка:
//конструкции разделяются запятыми, пробелы не допускаются
//вид конструкций:
//	ЧИСЛО - точное знечение
//	-ЧИСЛО - не больше
//	ЧИСЛО- - не меньше
//	ЧИСЛО-ЧИСЛО - от и до
//	!ЧИСЛО - за исключением
//	* - любое значение
	if(code=='*')return 'true';
	var s=code.split(','), s1;
	var t=[],o=[],m;
	//В цикле формируются две области: область, предписанная перечислением номеров
	//и область, представляющая разность множества целых числе и исключений
	for(var i=0;i<s.length;i++){
		if(m=s[i].match(/(\d+)-(\d+)/)){
			t.push('('+m[1]+'<='+varname+'&&'+varname+'<='+m[2]+')');
		}else if(m=s[i].match(/(\d+)-/)){
			t.push(m[1]+'<='+varname);
		}else if(m=s[i].match(/-(\d+)/)){
			t.push(m[1]+'>='+varname);
		}else if(m=s[i].match(/!(\d+)/)){
			o.push(m[1]+'!='+varname);
		}else if(m=s[i].match(/(\d+)/)){
			t.push(m[1]+'=='+varname);
		}
	}
	//результатом является пересечение двух найденных областей
	if(t.length>0) o.unshift('('+t.join(' \x7C\x7C ')+')'); //Если есть предписанные, их объединение добавляется в начало второй области для вычисления их пересечения.
	return (o.length>0) ? ('('+o.join(' && ')+')') : 'true'; //Защита от дурака - нужно ли?
}

function parseMultiEnum(config){
	var t=['true'];
	for(var j in config){
		t.push(parseEnum(config[j],j));
	}
	return t.join(' && ');
}

function TesterEnum(code){
	var F=new Function('x','return ' + parseEnum(code,'x'));
	F.superclass=TesterEnum;
	F.code=code;
	return F;
}

function testEnum(code,value){
	return eval(parseEnum(code,'value'));
}

function testEnumPath(path,pos){
	//path - путь или массив директив
	//	ЧИСЛО - точное знечение
	//	-ЧИСЛО - не больше
	//	ЧИСЛО- - не меньше
	//	ЧИСЛО-ЧИСЛО - от и до
	//	!ЧИСЛО - за исключением
	//	* - любое значение	
	//	** - любая цепочка значений (прекратить поиск и вернуть true)
	//	!* - нет элемента (проверить остались ли элементы, вернуть false - если остались, и true - если предыдущий был последним)
	
	//pos - массив значений, представляющий проверяемый путь
	
	//Если path задан строкой - разбиваем её по любым символам, не входящим в алфавит языка перечислений
	if(!(path instanceof Array)){
		if(path.split) path=path.split(/[^\d!\-*,]+/);	//годно
		else throw('')
	}
	
	for(var i=0;i<path.length;i++){
		if(path[i]=='**') break;
		else if(path[i]=='!*'){
			if(i<pos.length) return false;
			else break;
		}
		else if(i<pos.length){
			if(!testEnum(path[i],pos[i])) return false;
		}
		else return false;
	}
	return true;
}

function TesterEnumPath(path){
	//path - путь или массив директив
	//Если path задан строкой - разбиваем её по любым символам, не входящим в алфавит языка перечислений
	if(!(path instanceof Array)){
		if(path.split) path=path.split(/[^\d!\-*,]+/);	//годно
		else throw('')
	}
	
	var fun=[];
	for(var i=0;i<path.length;i++){
		if(path[i]=='!*'){
			fun[i]=(function(x){return !x && x!=0}); //проверить
			break;
		}
		else if(path[i]=='**'){
			fun[i]=(function(){return true});
			break;
		}
		else{
			fun[i]=TesterEnum(path[i]);
		}
	}
	
	F=function(pos){
		for(var i=0;i<fun.length;i++) if(!(fun[i])(pos[i])) return false;
		return true;
	};
	F.superclass=TesterEnumPath;
	F.path=path;
	return F;
}
//alert('ok');
