plugins/looptag/looptag.js
function(Template,expression,sort){
	var name,set,index;
	
	this.rawString = Noodles.Utilities.grabToEndSliceRaw(Template, expression,Template.language.tag('Loop'));
	this.needs = {};
	expression = expression.split(/\s+/g);
	if(expression.length < 2){
		this.skip = true;
		Noodles.Utilities.warning(Template,'Loop tag has bad syntax');
		return;
	}
	this.object = Noodles.Utilities.parseType(Template,expression[1]);
	if(!(this.object instanceof Noodles.Object)){
		this.skip = true;
		Noodles.Utilities.warning(Template,'Loop must have an object to loop over');
		delete this.object;
		return;
	}
	this.needs = Noodles.Utilities.mergeObjectWith(this.needs,this.object.needs);

	this.template = Noodles.Utilities.createSubTemplate(Template,this.rawString, this);
	if(this.template.needsCallback){
		this.skip = true;
		Noodles.Utilities.warning(Template,'Loop cannot contain any tags that will take a long time to run');
		delete this.template;
		return;
	}
	Template._leftCount++;//the end tag we sliced above
	this.sets = {};
	this.modifies = {};
	name = Template.language.other('name')
	this.name = new Noodles.Object(this.template,name);
	this.sets[name];
	this.modifies[name];
	value = Template.language.other('value');
	this.value = new Noodles.Object(this.template,value);
	index = '__' + Template.language.other('index')
	this.index = new Noodles.Object(this.template,index);
	this.sets[index];
	this.modifies[index];
	this.setExists = false;
	//<{loop foo as bar}>
	this.sort = !!sort;
	if(expression.length > 3 && (!this.sort || expression[2].toLowerCase() === Template.language.other('as'))){
		this.setObject = new Noodles.Object(this.template,expression[3]);
		if(this.setObject.order.length > 1){
			Noodles.Utilities.warning(Template,'Loop cannot set an object with multiple levels');
			this.skip = true;
			delete this.setObjet;
			return;
		}
		this.setExists = true;
	}
	
	if(this.sort){
		//<{sortloop foo as bar on baz}>
		if(expression.length > 5){
			this.sortKey = expression[5];
		}
		//<{sortloop foo on bar}>
		else if(expression.length > 3 && expression[2].toLowerCase() === Template.language.other('on')){
			this.sortKey = expression[3];
		}
		else{
			this.sortKey = Template.language.other('value');
		}
		//<{sortloop foo as bar on baz descending}>
		if(expression.length > 6){
			this.descending = expression[6].toLowerCase() === Template.language.other("descending");
		}
		//<{sortloop foo on bar descending}> or <{sortloop foo as bar descending}>
		else if(expression.length > 4 && expression[4].toLowerCase() === Template.language.other("descending")){
			this.descending = true;
		}
		//<{sortloop foo descending}>
		else if(expression.length > 2 && expression[2].toLowerCase() === Template.language.other("descending")){
			this.descending = true;
		}
		else{
			this.descending = false;
		}
	}
}
function(Template,expression,sort){
	var name,set,index;
	
	this.rawString = Noodles.Utilities.grabToEndSliceRaw(Template, expression,Template.language.tag('Loop'));
	this.needs = {};
	expression = expression.split(/\s+/g);
	if(expression.length < 2){
		this.skip = true;
		Noodles.Utilities.warning(Template,'Loop tag has bad syntax');
		return;
	}
	this.object = Noodles.Utilities.parseType(Template,expression[1]);
	if(!(this.object instanceof Noodles.Object)){
		this.skip = true;
		Noodles.Utilities.warning(Template,'Loop must have an object to loop over');
		delete this.object;
		return;
	}
	this.needs = Noodles.Utilities.mergeObjectWith(this.needs,this.object.needs);

	this.template = Noodles.Utilities.createSubTemplate(Template,this.rawString, this);
	if(this.template.needsCallback){
		this.skip = true;
		Noodles.Utilities.warning(Template,'Loop cannot contain any tags that will take a long time to run');
		delete this.template;
		return;
	}
	Template._leftCount++;//the end tag we sliced above
	this.sets = {};
	this.modifies = {};
	name = Template.language.other('name')
	this.name = new Noodles.Object(this.template,name);
	this.sets[name];
	this.modifies[name];
	value = Template.language.other('value');
	this.value = new Noodles.Object(this.template,value);
	index = '__' + Template.language.other('index')
	this.index = new Noodles.Object(this.template,index);
	this.sets[index];
	this.modifies[index];
	this.setExists = false;
	//<{loop foo as bar}>
	this.sort = !!sort;
	if(expression.length > 3 && (!this.sort || expression[2].toLowerCase() === Template.language.other('as'))){
		this.setObject = new Noodles.Object(this.template,expression[3]);
		if(this.setObject.order.length > 1){
			Noodles.Utilities.warning(Template,'Loop cannot set an object with multiple levels');
			this.skip = true;
			delete this.setObjet;
			return;
		}
		this.setExists = true;
	}
	
	if(this.sort){
		//<{sortloop foo as bar on baz}>
		if(expression.length > 5){
			this.sortKey = expression[5];
		}
		//<{sortloop foo on bar}>
		else if(expression.length > 3 && expression[2].toLowerCase() === Template.language.other('on')){
			this.sortKey = expression[3];
		}
		else{
			this.sortKey = Template.language.other('value');
		}
		//<{sortloop foo as bar on baz descending}>
		if(expression.length > 6){
			this.descending = expression[6].toLowerCase() === Template.language.other("descending");
		}
		//<{sortloop foo on bar descending}> or <{sortloop foo as bar descending}>
		else if(expression.length > 4 && expression[4].toLowerCase() === Template.language.other("descending")){
			this.descending = true;
		}
		//<{sortloop foo descending}>
		else if(expression.length > 2 && expression[2].toLowerCase() === Template.language.other("descending")){
			this.descending = true;
		}
		else{
			this.descending = false;
		}
	}
}
/*--module--
name: Loop
description: Loop object
@param {Noodles.Template}
@param {expression}
@param {bool}