<commit_before>/**
 * Copyright (c) 2014, the Railo Company Ltd.
 * Copyright (c) 2015, Lucee Assosication Switzerland
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either 
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public 
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package lucee.transformer.cfml.script;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import lucee.commons.lang.ExceptionUtil;
import lucee.commons.lang.StringUtil;
import lucee.commons.lang.types.RefBoolean;
import lucee.commons.lang.types.RefBooleanImpl;
import lucee.loader.engine.CFMLEngine;
import lucee.runtime.Component;
import lucee.runtime.PageSource;
import lucee.runtime.component.Member;
import lucee.runtime.config.Constants;
import lucee.runtime.exp.PageRuntimeException;
import lucee.runtime.exp.TemplateException;
import lucee.runtime.functions.system.CFFunction;
import lucee.runtime.op.Caster;
import lucee.runtime.type.util.ArrayUtil;
import lucee.runtime.type.util.ComponentUtil;
import lucee.transformer.Position;
import lucee.transformer.TransformerException;
import lucee.transformer.bytecode.Body;
import lucee.transformer.bytecode.BodyBase;
import lucee.transformer.bytecode.FunctionBody;
import lucee.transformer.bytecode.ScriptBody;
import lucee.transformer.bytecode.Statement;
import lucee.transformer.bytecode.cast.CastBoolean;
import lucee.transformer.bytecode.cast.CastOther;
import lucee.transformer.bytecode.expression.FunctionAsExpression;
import lucee.transformer.bytecode.expression.var.Assign;
import lucee.transformer.bytecode.statement.Argument;
import lucee.transformer.bytecode.statement.Condition;
import lucee.transformer.bytecode.statement.Condition.Pair;
import lucee.transformer.bytecode.statement.DoWhile;
import lucee.transformer.bytecode.statement.ExpressionAsStatement;
import lucee.transformer.bytecode.statement.For;
import lucee.transformer.bytecode.statement.ForEach;
import lucee.transformer.bytecode.statement.Return;
import lucee.transformer.bytecode.statement.Switch;
import lucee.transformer.bytecode.statement.TryCatchFinally;
import lucee.transformer.bytecode.statement.While;
import lucee.transformer.bytecode.statement.tag.Attribute;
import lucee.transformer.bytecode.statement.tag.Tag;
import lucee.transformer.bytecode.statement.tag.TagComponent;
import lucee.transformer.bytecode.statement.tag.TagOther;
import lucee.transformer.bytecode.statement.tag.TagParam;
import lucee.transformer.bytecode.statement.udf.Closure;
import lucee.transformer.bytecode.statement.udf.Function;
import lucee.transformer.bytecode.statement.udf.FunctionImpl;
import lucee.transformer.bytecode.statement.udf.Lambda;
import lucee.transformer.bytecode.util.ASMUtil;
import lucee.transformer.cfml.evaluator.EvaluatorException;
import lucee.transformer.cfml.evaluator.impl.ProcessingDirectiveException;
import lucee.transformer.cfml.expression.AbstrCFMLExprTransformer;
import lucee.transformer.cfml.tag.CFMLTransformer;
import lucee.transformer.expression.ExprBoolean;
import lucee.transformer.expression.Expression;
import lucee.transformer.expression.literal.LitBoolean;
import lucee.transformer.expression.var.Variable;
import lucee.transformer.library.function.FunctionLibFunction;
import lucee.transformer.library.tag.TagLib;
import lucee.transformer.library.tag.TagLibException;
import lucee.transformer.library.tag.TagLibTag;
import lucee.transformer.library.tag.TagLibTagAttr;
import lucee.transformer.library.tag.TagLibTagScript;
import lucee.transformer.util.PageSourceCode;
import lucee.transformer.util.SourceCode;


/**	
 * Innerhalb des Tag script kann in CFML eine eigene Scriptsprache verwendet werden, 
 * welche sich an Javascript orientiert. 
 * Da der data.srcCode Transformer keine Spezialfaelle zulaesst, 
 * also Tags einfach anhand der eingegeben TLD einliest und transformiert, 
 * aus diesem Grund wird der Inhalt des Tag script einfach als Zeichenkette eingelesen.
 * Erst durch den Evaluator (siehe 3.3), der fuer das Tag script definiert ist, 
 * wird der Inhalt des Tag script uebersetzt.
 * 
 */
public abstract class AbstrCFMLScriptTransformer extends AbstrCFMLExprTransformer {

	private static final String[] IGNORE_LIST_COMPONENT = new String[]{
		"output","synchronized","extends","implements","displayname","style","persistent","accessors"};
	private static final String[] IGNORE_LIST_INTERFACE = new String[]{
		"output","extends","displayname","style","persistent","accessors"};
	private static final String[] IGNORE_LIST_PROPERTY = new String[]{
		"default","fieldtype","name","type","persistent","remotingFetch","column","generator","length",
		"ormtype","params","unSavedValue","dbdefault","formula","generated","insert","optimisticlock",
		"update","notnull","precision","scale","unique","uniquekey","source"
	};
 

	private static EndCondition SEMI_BLOCK=new EndCondition() {
		@Override
		public boolean isEnd(ExprData data) {
			return data.srcCode.isCurrent('{') || data.srcCode.isCurrent(';');
		}
	};
	private static EndCondition SEMI=new EndCondition() {
		@Override
		public boolean isEnd(ExprData data) {
			return data.srcCode.isCurrent(';');
		}
	};
	private static EndCondition COMMA_ENDBRACKED=new EndCondition() {
		@Override
		public boolean isEnd(ExprData data) {
			return data.srcCode.isCurrent(',') || data.srcCode.isCurrent(')');
		}
	};
	
	private static EndCondition BRACKED=new EndCondition() {
		@Override
		public boolean isEnd(ExprData data) {
			return data.srcCode.isCurrent(')');
		}
	};
	
	
	
	

	private short ATTR_TYPE_NONE=TagLibTagAttr.SCRIPT_SUPPORT_NONE;
	private short ATTR_TYPE_OPTIONAL=TagLibTagAttr.SCRIPT_SUPPORT_OPTIONAL;
	private short ATTR_TYPE_REQUIRED=TagLibTagAttr.SCRIPT_SUPPORT_REQUIRED;
	
	public static class ComponentTemplateException extends TemplateException {
		private static final long serialVersionUID = -8103635220891288231L;
		
		private TemplateException te;

		public ComponentTemplateException(TemplateException te){
			super(te.getPageSource(),te.getLine(),0,te.getMessage());
			this.te=te;
			
		}

		/**
		 * @return the te
		 */
		public TemplateException getTemplateException() {
			return te;
		}
	}

	//private static final Expression NULL = data.factory.createLitString("NULL"); 
	//private static final Attribute ANY = new Attribute(false,"type",data.factory.createLitString("any"),"string"); 
	private static final char NO_ATTR_SEP = 0;
	
	/** 
	 * Liest saemtliche Statements des CFScriptString ein. 
	 * <br />
	 * EBNF:<br />
	 * <code>{statement spaces};</code>
	 * @return a statement
	 * @throws TemplateException
	 */
	protected final Body statements(ExprData data) throws TemplateException {
		ScriptBody body=new ScriptBody(data.factory);
		
		statements(data,body,true);
	return body;
	}
	
	/**
	 * Liest saemtliche Statements des CFScriptString ein. 
	 * <br />
	 * EBNF:<br />
	 * <code>{statement spaces};</code>
	 * @param parent uebergeornetes Element dem das Statement zugewiesen wird.
	 * @param isRoot befindet sich der Parser im root des data.srcCode Docs
	 * @throws TemplateException
	 */
	private final void statements(ExprData data,Body body, boolean isRoot) throws TemplateException {
		do {
			if(isRoot && isFinish(data))return;
			statement(data,body);
			comments(data);
		}
		while(data.srcCode.isValidIndex() && !data.srcCode.isCurrent('}'));
	}
	
	/** 
	 * Liest ein einzelnes Statement ein (if,for,while usw.).
	 * <br />
	 * EBNF:<br />
	 * <code>";" | "if" spaces "(" ifStatement | "function " funcStatement |  "while" spaces "(" whileStatement  |  
			  "do" spaces "{" doStatement  | "for" spaces "(" forStatement | "return" returnStatement | 
			  "break" breakStatement | "continue" continueStatement | "/*" comment | expressionStatement;</code>
	 * @param parent uebergeornetes Element dem das Statement zugewiesen wird.
	 * @throws TemplateException
	 */
	private final void statement(ExprData data,Body parent) throws TemplateException {
		statement(data, parent, data.context);
	}
	private boolean statement(ExprData data,Body parent,short context) throws TemplateException {
		short prior=data.context;
		data.context=context;
		comments(data);
		Statement child=null;
		if(data.srcCode.forwardIfCurrent(';')){return true;}
		else if((child=ifStatement(data))!=null) 				parent.addStatement(child);
		else if((child=propertyStatement(data,parent))!=null)	parent.addStatement(child);
		else if((child=paramStatement(data,parent))!=null)		parent.addStatement(child);
		//else if(funcStatement(data,parent)); // do nothing, happen already inside the method
		else if((child=funcStatement(data,parent))!=null)		parent.addStatement(child);
		else if((child=whileStatement(data))!=null) 			parent.addStatement(child);
		else if((child=doStatement(data))!=null) 				parent.addStatement(child);
		else if((child=forStatement(data))!=null) 				parent.addStatement(child);
		else if((child=returnStatement(data))!=null) 			parent.addStatement(child);
		else if((child=switchStatement(data))!=null) 			parent.addStatement(child);
		else if((child=tryStatement(data))!=null) 				parent.addStatement(child);
		//else if(staticStatement(data,parent)) ; // do nothing, happen already inside the method
		else if((child=staticStatement(data,parent))!=null)		parent.addStatement(child);
		else if((child=componentStatement(data,parent))!=null)	parent.addStatement(child);
		else if((child=tagStatement(data,parent))!=null)		parent.addStatement(child);
		else if((child=cftagStatement(data,parent))!=null)		parent.addStatement(child);
		else if(block(data,parent)){}
		
		else parent.addStatement(expressionStatement(data,parent));
		data.docComment=null;
		data.context=prior;
		
		return false;
	}
	

	/**
	 * Liest ein if Statement ein.
	 * <br />
	 * EBNF:<br />
	 * <code>spaces condition spaces ")" spaces block {"else if" spaces "(" elseifStatement spaces }
			 [("else"  spaces "(" | "else ") elseStatement spaces];</code>
	 * @return if Statement
	 * @throws TemplateException
	 */
	private final Statement ifStatement(ExprData data) throws TemplateException {
		if(!data.srcCode.forwardIfCurrent("if",'(')) return null;
		
		
		Position line = data.srcCode.getPosition();
		
		Body body=new BodyBase(data.factory);
		Condition cont=new Condition(data.factory,condition(data),body,line,null);
		
		if(!data.srcCode.forwardIfCurrent(')')) throw new TemplateException(data.srcCode,"if statement must end with a [)]");
		// ex block
		statement(data,body,CTX_IF);
		// else if
		comments(data);
		while(elseifStatement(data,cont)) {
			comments(data);
		}
		// else
		 if(elseStatement(data,cont)) {
			comments(data);
		 }

		cont.setEnd(data.srcCode.getPosition());
		return cont;
	}
	
	/**
	 * Liest ein else if Statement ein.
	 * <br />
	 * EBNF:<br />
	 * <code>spaces condition spaces ")" spaces block;</code>
	 * @return else if Statement
	 * @throws TemplateException
	 */
	private  final boolean elseifStatement(ExprData data,Condition cont) throws TemplateException {
		int pos=data.srcCode.getPos();
		if(!data.srcCode.forwardIfCurrent("else")) return false;
		
		comments(data);
		if(!data.srcCode.forwardIfCurrent("if",'(')) {
			data.srcCode.setPos(pos);
			return false;
		}
			
		Position line = data.srcCode.getPosition();
		Body body=new BodyBase(data.factory);
		Pair pair = cont.addElseIf(condition(data), body, line,null);

		if(!data.srcCode.forwardIfCurrent(')'))
			throw new TemplateException(data.srcCode,"else if statement must end with a [)]");
		// ex block
		statement(data,body,CTX_ELSE_IF);
		pair.end=data.srcCode.getPosition();
		return true;
	}
	
	/**
	 * Liest ein else Statement ein.
	 * <br />
	 * EBNF:<br />
	 * <code>block;</code>
	 * @return else Statement
	 * @throws TemplateException
	 * 
	 */
	private final boolean elseStatement(ExprData data,Condition cont) throws TemplateException {
		if(!data.srcCode.forwardIfCurrent("else",'{') && !data.srcCode.forwardIfCurrent("else ") && !data.srcCode.forwardIfCurrent("else",'/')) 
			return false;

		// start (
		data.srcCode.previous();
		// ex block
		Body body=new BodyBase(data.factory);
		Pair p = cont.setElse(body, data.srcCode.getPosition(),null);
		statement(data,body,CTX_ELSE);
		p.end=data.srcCode.getPosition();
		return true;
	}
	

	private final boolean finallyStatement(ExprData data,TryCatchFinally tcf) throws TemplateException {
		if(!data.srcCode.forwardIfCurrent("finally",'{') && !data.srcCode.forwardIfCurrent("finally ") && !data.srcCode.forwardIfCurrent("finally",'/')) 
			return false;

		// start (
		data.srcCode.previous();
		// ex block
		Body body=new BodyBase(data.factory);
		tcf.setFinally(body, data.srcCode.getPosition());
		statement(data,body,CTX_FINALLY);
		
		return true;
	}
	
	/**
	 * Liest ein while Statement ein.
	 * <br />
	 * EBNF:<br />
	 * <code>spaces condition spaces ")" spaces block;</code>
	 * @return while Statement
	 * @throws TemplateException
	 */
	private final While whileStatement(ExprData data) throws TemplateException {
		int pos=data.srcCode.getPos();
		
		// id
		String id=variableDec(data, false);
		if(id==null) {
			data.srcCode.setPos(pos);
			return null;
		}
		if(id.equalsIgnoreCase("while")){
			id=null;
			data.srcCode.removeSpace();
			if(!data.srcCode.forwardIfCurrent('(')){
				data.srcCode.setPos(pos);
				return null;
			}	
		}
		else {
			data.srcCode.removeSpace();
			if(!data.srcCode.forwardIfCurrent(':')){
				data.srcCode.setPos(pos);
				return null;
			}
			data.srcCode.removeSpace();
			
			if(!data.srcCode.forwardIfCurrent("while",'(')){
				data.srcCode.setPos(pos);
				return null;
			}
		}
		
		Position line = data.srcCode.getPosition();
		Body body=new BodyBase(data.factory);
		While whil=new While(condition(data),body,line,null,id);
		
		if(!data.srcCode.forwardIfCurrent(')'))
			throw new TemplateException(data.srcCode,"while statement must end with a [)]");
		
		statement(data,body,CTX_WHILE);
		whil.setEnd(data.srcCode.getPosition());
		return whil;
	}
	
	/**
	 * Liest ein switch Statment ein
	 * @return switch Statement
	 * @throws TemplateException
	 */
	private final Switch switchStatement(ExprData data) throws TemplateException {
		if(!data.srcCode.forwardIfCurrent("switch",'('))
			return null;
		
		Position line = data.srcCode.getPosition();
		
		comments(data);
		Expression expr = super.expression(data);
		comments(data);
		// end )
		if(!data.srcCode.forwardIfCurrent(')'))
			throw new TemplateException(data.srcCode,"switch statement must end with a [)]");
		comments(data);

		if(!data.srcCode.forwardIfCurrent('{'))
			throw new TemplateException(data.srcCode,"switch statement must have a starting  [{]");

		Switch swit=new Switch(expr,line,null);
		
		//	cases
		 //Node child=null;
		 comments(data);
		 while(caseStatement(data,swit)) {
			 comments(data);
		 }
		 // default
		  if(defaultStatement(data,swit)) {
			comments(data);
		  }
		  
		  while(caseStatement(data,swit)) {
				 comments(data);
			 }
		  
		  
		// }
		if(!data.srcCode.forwardIfCurrent('}'))
			throw new TemplateException(data.srcCode,"invalid construct in switch statement");
		swit.setEnd(data.srcCode.getPosition());
		return swit;
	}
	
	
	private final TagComponent componentStatement(ExprData data, Body parent) throws TemplateException {
		
		int pos = data.srcCode.getPos();
		
		// get the idendifier in front of
		String id=identifier(data, false);
		if(id==null) {
			data.srcCode.setPos(pos);
			return null;
		}
		
		int mod=ComponentUtil.toModifier(id, Component.MODIFIER_NONE, Component.MODIFIER_NONE);
		if(mod==Component.MODIFIER_NONE) {
			data.srcCode.setPos(pos); 
		}
		
		comments(data);

		// do we have a starting component?
		if(
				!data.srcCode.isCurrent(getComponentName(data.srcCode.getDialect()))
				&& 
				(data.srcCode.getDialect()==CFMLEngine.DIALECT_CFML || !data.srcCode.isCurrent(Constants.CFML_COMPONENT_TAG_NAME))) {
			data.srcCode.setPos(pos);
			return null;
		}
		
		// parse the component
		TagLibTag tlt = CFMLTransformer.getTLT(data.srcCode,getComponentName(data.srcCode.getDialect()),
						data.config.getIdentification());
		TagComponent comp =(TagComponent) _multiAttrStatement(parent, data, tlt);
		if(mod!=Component.MODIFIER_NONE)comp.addAttribute(new Attribute(false,"modifier",data.factory.createLitString(id),"string"));
		return comp;
	}
	
	private String getComponentName(int dialect) {
		return dialect==CFMLEngine.DIALECT_LUCEE?Constants.LUCEE_COMPONENT_TAG_NAME:Constants.CFML_COMPONENT_TAG_NAME;
	}

	/**
	 * Liest ein Case Statement ein
	 * @return case Statement
	 * @throws TemplateException
	 */
	private final boolean caseStatement(ExprData data,Switch swit) throws TemplateException {
		if(!data.srcCode.forwardIfCurrentAndNoWordAfter("case"))
			return false;
		
		//int line=data.srcCode.getLine();		
		comments(data);
		Expression expr = super.expression(data);
		comments(data);
		
		if(!data.srcCode.forwardIfCurrent(':'))
			throw new TemplateException(data.srcCode,"case body must start with [:]");
		
		Body body=new BodyBase(data.factory);
		switchBlock(data,body);
		swit.addCase(expr, body);
		return true;
	}
	
	/**
	 * Liest ein default Statement ein
	 * @return default Statement
	 * @throws TemplateException
	 */
	private final boolean defaultStatement(ExprData data,Switch swit) throws TemplateException {
		if(!data.srcCode.forwardIfCurrent("default",':'))
			return false;
		
		//int line=data.srcCode.getLine();
		
		Body body=new BodyBase(data.factory);
		swit.setDefaultCase(body);
		switchBlock(data,body);
		return true;
	}
	
	/**
	 * Liest ein Switch Block ein
	 * @param block
	 * @throws TemplateException
	 */
	private final void switchBlock(ExprData data,Body body) throws TemplateException {
		while(data.srcCode.isValidIndex()) {
			comments(data);
			if(data.srcCode.isCurrent("case ") || data.srcCode.isCurrent("default",':') || data.srcCode.isCurrent('}')) 
				return;
			statement(data,body,CTX_SWITCH);
		}
	}
	
	
	/**
	 * Liest ein do Statement ein.
	 * <br />
	 * EBNF:<br />
	 * <code>block spaces "while" spaces "(" spaces condition spaces ")";</code>
	 * @return do Statement
	 * @throws TemplateException
	 */
	private final DoWhile doStatement(ExprData data) throws TemplateException {
		int pos=data.srcCode.getPos();
		
		// id
		String id=variableDec(data, false);
		if(id==null) {
			data.srcCode.setPos(pos);
			return null;
		}
		if(id.equalsIgnoreCase("do")){
			id=null;
			if(!data.srcCode.isCurrent('{') && !data.srcCode.isCurrent(' ') && !data.srcCode.isCurrent('/')) {
				data.srcCode.setPos(pos);
				return null;
			}	
		}
		else {
			data.srcCode.removeSpace();
			if(!data.srcCode.forwardIfCurrent(':')){
				data.srcCode.setPos(pos);
				return null;
			}
			data.srcCode.removeSpace();
			
			if(!data.srcCode.forwardIfCurrent("do",'{') && !data.srcCode.forwardIfCurrent("do ") && !data.srcCode.forwardIfCurrent("do",'/')) {
				data.srcCode.setPos(pos);
				return null;
			}
			data.srcCode.previous();
		}
		
		//if(!data.srcCode.forwardIfCurrent("do",'{') && !data.srcCode.forwardIfCurrent("do ") && !data.srcCode.forwardIfCurrent("do",'/'))
		//	return null;
		
		Position line = data.srcCode.getPosition();
		Body body=new BodyBase(data.factory);
		
		//data.srcCode.previous();
		statement(data,body,CTX_DO_WHILE);
		
		
		comments(data);
		if(!data.srcCode.forwardIfCurrent("while",'('))
			throw new TemplateException(data.srcCode,"do statement must have a while at the end");
		
		DoWhile doWhile=new DoWhile(condition(data),body,line,data.srcCode.getPosition(),id);
		
		if(!data.srcCode.forwardIfCurrent(')'))
			throw new TemplateException(data.srcCode,"do statement must end with a [)]");
		
		
		return doWhile;
	}
	
	/**
	 * Liest ein for Statement ein.
	 * <br />
	 * EBNF:<br />
	 * <code>expression spaces ";" spaces condition spaces ";" spaces expression spaces ")" spaces block;</code>
	 * @return for Statement
	 * @throws TemplateException
	 */
	private final Statement forStatement(ExprData data) throws TemplateException {
		
		int pos=data.srcCode.getPos();
		
		// id
		String id=variableDec(data, false);
		if(id==null) {
			data.srcCode.setPos(pos);
			return null;
		}
		if(id.equalsIgnoreCase("for")){
			id=null;
			data.srcCode.removeSpace();
			if(!data.srcCode.forwardIfCurrent('(')){
				data.srcCode.setPos(pos);
				return null;
			}	
		}
		else {
			data.srcCode.removeSpace();
			if(!data.srcCode.forwardIfCurrent(':')){
				data.srcCode.setPos(pos);
				return null;
			}
			data.srcCode.removeSpace();
			
			if(!data.srcCode.forwardIfCurrent("for",'(')){
				data.srcCode.setPos(pos);
				return null;
			}
		}
		
		
		
		
		//if(!data.srcCode.forwardIfCurrent("for",'(')) 
		//	return null;
		
		
		
		Expression left=null;
		Body body=new BodyBase(data.factory);
		Position line = data.srcCode.getPosition();
		comments(data);
		if(!data.srcCode.isCurrent(';')) {
			// left
			left=expression(data);
			comments(data);
		}
		// middle for
			if(data.srcCode.forwardIfCurrent(';')) {

				Expression cont=null;
				Expression update=null;
				// condition
					comments(data);
					if(!data.srcCode.isCurrent(';')) {
						cont=condition(data);
						comments(data);
					}
				// middle
				if(!data.srcCode.forwardIfCurrent(';'))
					throw new TemplateException(data.srcCode,"invalid syntax in for statement");
				// update
					comments(data);
					if(!data.srcCode.isCurrent(')')) {
						update=expression(data);
						comments(data);
					}
				// start )
				if(!data.srcCode.forwardIfCurrent(')'))
					throw new TemplateException(data.srcCode,"invalid syntax in for statement, for statement must end with a [)]");
				// ex block
				statement(data,body,CTX_FOR);
		
				return new For(data.factory,left,cont,update,body,line,data.srcCode.getPosition(),id);					
			}
		// middle foreach
			else if(data.srcCode.forwardIfCurrent("in")) {
				// condition
					comments(data);
					Expression value = expression(data);
					comments(data);
				if(!data.srcCode.forwardIfCurrent(')'))
					throw new TemplateException(data.srcCode,"invalid syntax in for statement, for statement must end with a [)]");
				
				// ex block
				statement(data,body,CTX_FOR);
				if(!(left instanceof Variable))
					throw new TemplateException(data.srcCode,"invalid syntax in for statement, left value is invalid");
				
				//if(!(value instanceof Variable))
				//	throw new TemplateException(data.srcCode,"invalid syntax in for statement, right value is invalid");
				return new ForEach((Variable)left,value,body,line,data.srcCode.getPosition(),id);	
			}
			else 
				throw new TemplateException(data.srcCode,"invalid syntax in for statement");
	}
	
	/**
	 * Liest ein function Statement ein.
	 * <br />
	 * EBNF:<br />
	 * <code>identifier spaces "(" spaces identifier spaces {"," spaces identifier spaces} ")" spaces block;</code>
	 * @return function Statement
	 * @throws TemplateException
	 */
	private final Statement funcStatement(ExprData data,Body parent) throws TemplateException {
		int pos=data.srcCode.getPos();
		
		// read 5 tokens (returntype,access modifier,"abstract|final|static","function", function name)
		String str=variableDec(data, false);
		// if there is no token at all we have no function
		if(str==null) {
			data.srcCode.setPos(pos);
			return null;
		}
		comments(data);
		String[] tokens=new String[]{str,null,null,null,null};
		
		tokens[1]=variableDec(data, false);
		comments(data);
		if(tokens[1]!=null){
			tokens[2]=variableDec(data, false);
			comments(data);
			if(tokens[2]!=null){<commit_msg>initial work to make for faster<commit_after>/**
 * Copyright (c) 2014, the Railo Company Ltd.
 * Copyright (c) 2015, Lucee Assosication Switzerland
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either 
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public 
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package lucee.transformer.cfml.script;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import lucee.print;
import lucee.commons.lang.ExceptionUtil;
import lucee.commons.lang.StringUtil;
import lucee.commons.lang.types.RefBoolean;
import lucee.commons.lang.types.RefBooleanImpl;
import lucee.loader.engine.CFMLEngine;
import lucee.runtime.Component;
import lucee.runtime.PageSource;
import lucee.runtime.component.Member;
import lucee.runtime.config.Constants;
import lucee.runtime.exp.PageRuntimeException;
import lucee.runtime.exp.TemplateException;
import lucee.runtime.functions.system.CFFunction;
import lucee.runtime.op.Caster;
import lucee.runtime.type.util.ArrayUtil;
import lucee.runtime.type.util.ComponentUtil;
import lucee.transformer.Factory;
import lucee.transformer.Position;
import lucee.transformer.TransformerException;
import lucee.transformer.bytecode.Body;
import lucee.transformer.bytecode.BodyBase;
import lucee.transformer.bytecode.FunctionBody;
import lucee.transformer.bytecode.ScriptBody;
import lucee.transformer.bytecode.Statement;
import lucee.transformer.bytecode.cast.CastBoolean;
import lucee.transformer.bytecode.cast.CastOther;
import lucee.transformer.bytecode.expression.FunctionAsExpression;
import lucee.transformer.bytecode.expression.var.Assign;
import lucee.transformer.bytecode.expression.var.VariableString;
import lucee.transformer.bytecode.op.OPDecision;
import lucee.transformer.bytecode.op.OpDouble;
import lucee.transformer.bytecode.statement.Argument;
import lucee.transformer.bytecode.statement.Condition;
import lucee.transformer.bytecode.statement.Condition.Pair;
import lucee.transformer.bytecode.statement.DoWhile;
import lucee.transformer.bytecode.statement.ExpressionAsStatement;
import lucee.transformer.bytecode.statement.For;
import lucee.transformer.bytecode.statement.ForEach;
import lucee.transformer.bytecode.statement.Return;
import lucee.transformer.bytecode.statement.Switch;
import lucee.transformer.bytecode.statement.TryCatchFinally;
import lucee.transformer.bytecode.statement.While;
import lucee.transformer.bytecode.statement.tag.Attribute;
import lucee.transformer.bytecode.statement.tag.Tag;
import lucee.transformer.bytecode.statement.tag.TagComponent;
import lucee.transformer.bytecode.statement.tag.TagLoop;
import lucee.transformer.bytecode.statement.tag.TagOther;
import lucee.transformer.bytecode.statement.tag.TagParam;
import lucee.transformer.bytecode.statement.udf.Closure;
import lucee.transformer.bytecode.statement.udf.Function;
import lucee.transformer.bytecode.statement.udf.FunctionImpl;
import lucee.transformer.bytecode.statement.udf.Lambda;
import lucee.transformer.bytecode.util.ASMUtil;
import lucee.transformer.cfml.evaluator.EvaluatorException;
import lucee.transformer.cfml.evaluator.impl.Loop;
import lucee.transformer.cfml.evaluator.impl.ProcessingDirectiveException;
import lucee.transformer.cfml.expression.AbstrCFMLExprTransformer;
import lucee.transformer.cfml.tag.CFMLTransformer;
import lucee.transformer.expression.ExprBoolean;
import lucee.transformer.expression.Expression;
import lucee.transformer.expression.literal.LitBoolean;
import lucee.transformer.expression.literal.LitDouble;
import lucee.transformer.expression.literal.LitString;
import lucee.transformer.expression.var.Variable;
import lucee.transformer.library.function.FunctionLibFunction;
import lucee.transformer.library.tag.TagLib;
import lucee.transformer.library.tag.TagLibException;
import lucee.transformer.library.tag.TagLibTag;
import lucee.transformer.library.tag.TagLibTagAttr;
import lucee.transformer.library.tag.TagLibTagScript;
import lucee.transformer.util.PageSourceCode;
import lucee.transformer.util.SourceCode;


/**	
 * Innerhalb des Tag script kann in CFML eine eigene Scriptsprache verwendet werden, 
 * welche sich an Javascript orientiert. 
 * Da der data.srcCode Transformer keine Spezialfaelle zulaesst, 
 * also Tags einfach anhand der eingegeben TLD einliest und transformiert, 
 * aus diesem Grund wird der Inhalt des Tag script einfach als Zeichenkette eingelesen.
 * Erst durch den Evaluator (siehe 3.3), der fuer das Tag script definiert ist, 
 * wird der Inhalt des Tag script uebersetzt.
 * 
 */
public abstract class AbstrCFMLScriptTransformer extends AbstrCFMLExprTransformer {

	private static final String[] IGNORE_LIST_COMPONENT = new String[]{
		"output","synchronized","extends","implements","displayname","style","persistent","accessors"};
	private static final String[] IGNORE_LIST_INTERFACE = new String[]{
		"output","extends","displayname","style","persistent","accessors"};
	private static final String[] IGNORE_LIST_PROPERTY = new String[]{
		"default","fieldtype","name","type","persistent","remotingFetch","column","generator","length",
		"ormtype","params","unSavedValue","dbdefault","formula","generated","insert","optimisticlock",
		"update","notnull","precision","scale","unique","uniquekey","source"
	};
 

	private static EndCondition SEMI_BLOCK=new EndCondition() {
		@Override
		public boolean isEnd(ExprData data) {
			return data.srcCode.isCurrent('{') || data.srcCode.isCurrent(';');
		}
	};
	private static EndCondition SEMI=new EndCondition() {
		@Override
		public boolean isEnd(ExprData data) {
			return data.srcCode.isCurrent(';');
		}
	};
	private static EndCondition COMMA_ENDBRACKED=new EndCondition() {
		@Override
		public boolean isEnd(ExprData data) {
			return data.srcCode.isCurrent(',') || data.srcCode.isCurrent(')');
		}
	};
	
	private static EndCondition BRACKED=new EndCondition() {
		@Override
		public boolean isEnd(ExprData data) {
			return data.srcCode.isCurrent(')');
		}
	};
	
	
	
	

	private short ATTR_TYPE_NONE=TagLibTagAttr.SCRIPT_SUPPORT_NONE;
	private short ATTR_TYPE_OPTIONAL=TagLibTagAttr.SCRIPT_SUPPORT_OPTIONAL;
	private short ATTR_TYPE_REQUIRED=TagLibTagAttr.SCRIPT_SUPPORT_REQUIRED;
	
	public static class ComponentTemplateException extends TemplateException {
		private static final long serialVersionUID = -8103635220891288231L;
		
		private TemplateException te;

		public ComponentTemplateException(TemplateException te){
			super(te.getPageSource(),te.getLine(),0,te.getMessage());
			this.te=te;
			
		}

		/**
		 * @return the te
		 */
		public TemplateException getTemplateException() {
			return te;
		}
	}

	//private static final Expression NULL = data.factory.createLitString("NULL"); 
	//private static final Attribute ANY = new Attribute(false,"type",data.factory.createLitString("any"),"string"); 
	private static final char NO_ATTR_SEP = 0;
	
	/** 
	 * Liest saemtliche Statements des CFScriptString ein. 
	 * <br />
	 * EBNF:<br />
	 * <code>{statement spaces};</code>
	 * @return a statement
	 * @throws TemplateException
	 */
	protected final Body statements(ExprData data) throws TemplateException {
		ScriptBody body=new ScriptBody(data.factory);
		
		statements(data,body,true);
	return body;
	}
	
	/**
	 * Liest saemtliche Statements des CFScriptString ein. 
	 * <br />
	 * EBNF:<br />
	 * <code>{statement spaces};</code>
	 * @param parent uebergeornetes Element dem das Statement zugewiesen wird.
	 * @param isRoot befindet sich der Parser im root des data.srcCode Docs
	 * @throws TemplateException
	 */
	private final void statements(ExprData data,Body body, boolean isRoot) throws TemplateException {
		do {
			if(isRoot && isFinish(data))return;
			statement(data,body);
			comments(data);
		}
		while(data.srcCode.isValidIndex() && !data.srcCode.isCurrent('}'));
	}
	
	/** 
	 * Liest ein einzelnes Statement ein (if,for,while usw.).
	 * <br />
	 * EBNF:<br />
	 * <code>";" | "if" spaces "(" ifStatement | "function " funcStatement |  "while" spaces "(" whileStatement  |  
			  "do" spaces "{" doStatement  | "for" spaces "(" forStatement | "return" returnStatement | 
			  "break" breakStatement | "continue" continueStatement | "/*" comment | expressionStatement;</code>
	 * @param parent uebergeornetes Element dem das Statement zugewiesen wird.
	 * @throws TemplateException
	 */
	private final void statement(ExprData data,Body parent) throws TemplateException {
		statement(data, parent, data.context);
	}
	private boolean statement(ExprData data,Body parent,short context) throws TemplateException {
		short prior=data.context;
		data.context=context;
		comments(data);
		Statement child=null;
		if(data.srcCode.forwardIfCurrent(';')){return true;}
		else if((child=ifStatement(data))!=null) 				parent.addStatement(child);
		else if((child=propertyStatement(data,parent))!=null)	parent.addStatement(child);
		else if((child=paramStatement(data,parent))!=null)		parent.addStatement(child);
		//else if(funcStatement(data,parent)); // do nothing, happen already inside the method
		else if((child=funcStatement(data,parent))!=null)		parent.addStatement(child);
		else if((child=whileStatement(data))!=null) 			parent.addStatement(child);
		else if((child=doStatement(data))!=null) 				parent.addStatement(child);
		else if((child=forStatement(data))!=null) 				parent.addStatement(child);
		else if((child=returnStatement(data))!=null) 			parent.addStatement(child);
		else if((child=switchStatement(data))!=null) 			parent.addStatement(child);
		else if((child=tryStatement(data))!=null) 				parent.addStatement(child);
		//else if(staticStatement(data,parent)) ; // do nothing, happen already inside the method
		else if((child=staticStatement(data,parent))!=null)		parent.addStatement(child);
		else if((child=componentStatement(data,parent))!=null)	parent.addStatement(child);
		else if((child=tagStatement(data,parent))!=null)		parent.addStatement(child);
		else if((child=cftagStatement(data,parent))!=null)		parent.addStatement(child);
		else if(block(data,parent)){}
		
		else parent.addStatement(expressionStatement(data,parent));
		data.docComment=null;
		data.context=prior;
		
		return false;
	}
	

	/**
	 * Liest ein if Statement ein.
	 * <br />
	 * EBNF:<br />
	 * <code>spaces condition spaces ")" spaces block {"else if" spaces "(" elseifStatement spaces }
			 [("else"  spaces "(" | "else ") elseStatement spaces];</code>
	 * @return if Statement
	 * @throws TemplateException
	 */
	private final Statement ifStatement(ExprData data) throws TemplateException {
		if(!data.srcCode.forwardIfCurrent("if",'(')) return null;
		
		
		Position line = data.srcCode.getPosition();
		
		Body body=new BodyBase(data.factory);
		Condition cont=new Condition(data.factory,condition(data),body,line,null);
		
		if(!data.srcCode.forwardIfCurrent(')')) throw new TemplateException(data.srcCode,"if statement must end with a [)]");
		// ex block
		statement(data,body,CTX_IF);
		// else if
		comments(data);
		while(elseifStatement(data,cont)) {
			comments(data);
		}
		// else
		 if(elseStatement(data,cont)) {
			comments(data);
		 }

		cont.setEnd(data.srcCode.getPosition());
		return cont;
	}
	
	/**
	 * Liest ein else if Statement ein.
	 * <br />
	 * EBNF:<br />
	 * <code>spaces condition spaces ")" spaces block;</code>
	 * @return else if Statement
	 * @throws TemplateException
	 */
	private  final boolean elseifStatement(ExprData data,Condition cont) throws TemplateException {
		int pos=data.srcCode.getPos();
		if(!data.srcCode.forwardIfCurrent("else")) return false;
		
		comments(data);
		if(!data.srcCode.forwardIfCurrent("if",'(')) {
			data.srcCode.setPos(pos);
			return false;
		}
			
		Position line = data.srcCode.getPosition();
		Body body=new BodyBase(data.factory);
		Pair pair = cont.addElseIf(condition(data), body, line,null);

		if(!data.srcCode.forwardIfCurrent(')'))
			throw new TemplateException(data.srcCode,"else if statement must end with a [)]");
		// ex block
		statement(data,body,CTX_ELSE_IF);
		pair.end=data.srcCode.getPosition();
		return true;
	}
	
	/**
	 * Liest ein else Statement ein.
	 * <br />
	 * EBNF:<br />
	 * <code>block;</code>
	 * @return else Statement
	 * @throws TemplateException
	 * 
	 */
	private final boolean elseStatement(ExprData data,Condition cont) throws TemplateException {
		if(!data.srcCode.forwardIfCurrent("else",'{') && !data.srcCode.forwardIfCurrent("else ") && !data.srcCode.forwardIfCurrent("else",'/')) 
			return false;

		// start (
		data.srcCode.previous();
		// ex block
		Body body=new BodyBase(data.factory);
		Pair p = cont.setElse(body, data.srcCode.getPosition(),null);
		statement(data,body,CTX_ELSE);
		p.end=data.srcCode.getPosition();
		return true;
	}
	

	private final boolean finallyStatement(ExprData data,TryCatchFinally tcf) throws TemplateException {
		if(!data.srcCode.forwardIfCurrent("finally",'{') && !data.srcCode.forwardIfCurrent("finally ") && !data.srcCode.forwardIfCurrent("finally",'/')) 
			return false;

		// start (
		data.srcCode.previous();
		// ex block
		Body body=new BodyBase(data.factory);
		tcf.setFinally(body, data.srcCode.getPosition());
		statement(data,body,CTX_FINALLY);
		
		return true;
	}
	
	/**
	 * Liest ein while Statement ein.
	 * <br />
	 * EBNF:<br />
	 * <code>spaces condition spaces ")" spaces block;</code>
	 * @return while Statement
	 * @throws TemplateException
	 */
	private final While whileStatement(ExprData data) throws TemplateException {
		int pos=data.srcCode.getPos();
		
		// id
		String id=variableDec(data, false);
		if(id==null) {
			data.srcCode.setPos(pos);
			return null;
		}
		if(id.equalsIgnoreCase("while")){
			id=null;
			data.srcCode.removeSpace();
			if(!data.srcCode.forwardIfCurrent('(')){
				data.srcCode.setPos(pos);
				return null;
			}	
		}
		else {
			data.srcCode.removeSpace();
			if(!data.srcCode.forwardIfCurrent(':')){
				data.srcCode.setPos(pos);
				return null;
			}
			data.srcCode.removeSpace();
			
			if(!data.srcCode.forwardIfCurrent("while",'(')){
				data.srcCode.setPos(pos);
				return null;
			}
		}
		
		Position line = data.srcCode.getPosition();
		Body body=new BodyBase(data.factory);
		While whil=new While(condition(data),body,line,null,id);
		
		if(!data.srcCode.forwardIfCurrent(')'))
			throw new TemplateException(data.srcCode,"while statement must end with a [)]");
		
		statement(data,body,CTX_WHILE);
		whil.setEnd(data.srcCode.getPosition());
		return whil;
	}
	
	/**
	 * Liest ein switch Statment ein
	 * @return switch Statement
	 * @throws TemplateException
	 */
	private final Switch switchStatement(ExprData data) throws TemplateException {
		if(!data.srcCode.forwardIfCurrent("switch",'('))
			return null;
		
		Position line = data.srcCode.getPosition();
		
		comments(data);
		Expression expr = super.expression(data);
		comments(data);
		// end )
		if(!data.srcCode.forwardIfCurrent(')'))
			throw new TemplateException(data.srcCode,"switch statement must end with a [)]");
		comments(data);

		if(!data.srcCode.forwardIfCurrent('{'))
			throw new TemplateException(data.srcCode,"switch statement must have a starting  [{]");

		Switch swit=new Switch(expr,line,null);
		
		//	cases
		 //Node child=null;
		 comments(data);
		 while(caseStatement(data,swit)) {
			 comments(data);
		 }
		 // default
		  if(defaultStatement(data,swit)) {
			comments(data);
		  }
		  
		  while(caseStatement(data,swit)) {
				 comments(data);
			 }
		  
		  
		// }
		if(!data.srcCode.forwardIfCurrent('}'))
			throw new TemplateException(data.srcCode,"invalid construct in switch statement");
		swit.setEnd(data.srcCode.getPosition());
		return swit;
	}
	
	
	private final TagComponent componentStatement(ExprData data, Body parent) throws TemplateException {
		
		int pos = data.srcCode.getPos();
		
		// get the idendifier in front of
		String id=identifier(data, false);
		if(id==null) {
			data.srcCode.setPos(pos);
			return null;
		}
		
		int mod=ComponentUtil.toModifier(id, Component.MODIFIER_NONE, Component.MODIFIER_NONE);
		if(mod==Component.MODIFIER_NONE) {
			data.srcCode.setPos(pos); 
		}
		
		comments(data);

		// do we have a starting component?
		if(
				!data.srcCode.isCurrent(getComponentName(data.srcCode.getDialect()))
				&& 
				(data.srcCode.getDialect()==CFMLEngine.DIALECT_CFML || !data.srcCode.isCurrent(Constants.CFML_COMPONENT_TAG_NAME))) {
			data.srcCode.setPos(pos);
			return null;
		}
		
		// parse the component
		TagLibTag tlt = CFMLTransformer.getTLT(data.srcCode,getComponentName(data.srcCode.getDialect()),
						data.config.getIdentification());
		TagComponent comp =(TagComponent) _multiAttrStatement(parent, data, tlt);
		if(mod!=Component.MODIFIER_NONE)comp.addAttribute(new Attribute(false,"modifier",data.factory.createLitString(id),"string"));
		return comp;
	}
	
	private String getComponentName(int dialect) {
		return dialect==CFMLEngine.DIALECT_LUCEE?Constants.LUCEE_COMPONENT_TAG_NAME:Constants.CFML_COMPONENT_TAG_NAME;
	}

	/**
	 * Liest ein Case Statement ein
	 * @return case Statement
	 * @throws TemplateException
	 */
	private final boolean caseStatement(ExprData data,Switch swit) throws TemplateException {
		if(!data.srcCode.forwardIfCurrentAndNoWordAfter("case"))
			return false;
		
		//int line=data.srcCode.getLine();		
		comments(data);
		Expression expr = super.expression(data);
		comments(data);
		
		if(!data.srcCode.forwardIfCurrent(':'))
			throw new TemplateException(data.srcCode,"case body must start with [:]");
		
		Body body=new BodyBase(data.factory);
		switchBlock(data,body);
		swit.addCase(expr, body);
		return true;
	}
	
	/**
	 * Liest ein default Statement ein
	 * @return default Statement
	 * @throws TemplateException
	 */
	private final boolean defaultStatement(ExprData data,Switch swit) throws TemplateException {
		if(!data.srcCode.forwardIfCurrent("default",':'))
			return false;
		
		//int line=data.srcCode.getLine();
		
		Body body=new BodyBase(data.factory);
		swit.setDefaultCase(body);
		switchBlock(data,body);
		return true;
	}
	
	/**
	 * Liest ein Switch Block ein
	 * @param block
	 * @throws TemplateException
	 */
	private final void switchBlock(ExprData data,Body body) throws TemplateException {
		while(data.srcCode.isValidIndex()) {
			comments(data);
			if(data.srcCode.isCurrent("case ") || data.srcCode.isCurrent("default",':') || data.srcCode.isCurrent('}')) 
				return;
			statement(data,body,CTX_SWITCH);
		}
	}
	
	
	/**
	 * Liest ein do Statement ein.
	 * <br />
	 * EBNF:<br />
	 * <code>block spaces "while" spaces "(" spaces condition spaces ")";</code>
	 * @return do Statement
	 * @throws TemplateException
	 */
	private final DoWhile doStatement(ExprData data) throws TemplateException {
		int pos=data.srcCode.getPos();
		
		// id
		String id=variableDec(data, false);
		if(id==null) {
			data.srcCode.setPos(pos);
			return null;
		}
		if(id.equalsIgnoreCase("do")){
			id=null;
			if(!data.srcCode.isCurrent('{') && !data.srcCode.isCurrent(' ') && !data.srcCode.isCurrent('/')) {
				data.srcCode.setPos(pos);
				return null;
			}	
		}
		else {
			data.srcCode.removeSpace();
			if(!data.srcCode.forwardIfCurrent(':')){
				data.srcCode.setPos(pos);
				return null;
			}
			data.srcCode.removeSpace();
			
			if(!data.srcCode.forwardIfCurrent("do",'{') && !data.srcCode.forwardIfCurrent("do ") && !data.srcCode.forwardIfCurrent("do",'/')) {
				data.srcCode.setPos(pos);
				return null;
			}
			data.srcCode.previous();
		}
		
		//if(!data.srcCode.forwardIfCurrent("do",'{') && !data.srcCode.forwardIfCurrent("do ") && !data.srcCode.forwardIfCurrent("do",'/'))
		//	return null;
		
		Position line = data.srcCode.getPosition();
		Body body=new BodyBase(data.factory);
		
		//data.srcCode.previous();
		statement(data,body,CTX_DO_WHILE);
		
		
		comments(data);
		if(!data.srcCode.forwardIfCurrent("while",'('))
			throw new TemplateException(data.srcCode,"do statement must have a while at the end");
		
		DoWhile doWhile=new DoWhile(condition(data),body,line,data.srcCode.getPosition(),id);
		
		if(!data.srcCode.forwardIfCurrent(')'))
			throw new TemplateException(data.srcCode,"do statement must end with a [)]");
		
		
		return doWhile;
	}
	
	/**
	 * Liest ein for Statement ein.
	 * <br />
	 * EBNF:<br />
	 * <code>expression spaces ";" spaces condition spaces ";" spaces expression spaces ")" spaces block;</code>
	 * @return for Statement
	 * @throws TemplateException
	 */
	private final Statement forStatement(ExprData data) throws TemplateException {
		
		int pos=data.srcCode.getPos();
		
		// id
		String id=variableDec(data, false);
		if(id==null) {
			data.srcCode.setPos(pos);
			return null;
		}
		if(id.equalsIgnoreCase("for")){
			id=null;
			data.srcCode.removeSpace();
			if(!data.srcCode.forwardIfCurrent('(')){
				data.srcCode.setPos(pos);
				return null;
			}	
		}
		else {
			data.srcCode.removeSpace();
			if(!data.srcCode.forwardIfCurrent(':')){
				data.srcCode.setPos(pos);
				return null;
			}
			data.srcCode.removeSpace();
			
			if(!data.srcCode.forwardIfCurrent("for",'(')){
				data.srcCode.setPos(pos);
				return null;
			}
		}
		
		
		
		
		//if(!data.srcCode.forwardIfCurrent("for",'(')) 
		//	return null;
		
		
		
		Expression left=null;
		Body body=new BodyBase(data.factory);
		Position line = data.srcCode.getPosition();
		comments(data);
		if(!data.srcCode.isCurrent(';')) {
			// left
			left=expression(data);
			comments(data);
		}
		// middle for
			if(data.srcCode.forwardIfCurrent(';')) {

				Expression cont=null;
				Expression update=null;
				// condition
					comments(data);
					if(!data.srcCode.isCurrent(';')) {
						cont=condition(data);
						comments(data);
					}
				// middle
				if(!data.srcCode.forwardIfCurrent(';'))
					throw new TemplateException(data.srcCode,"invalid syntax in for statement");
				// update
					comments(data);
					if(!data.srcCode.isCurrent(')')) {
						update=expression(data);
						comments(data);
					}
				// start )
				if(!data.srcCode.forwardIfCurrent(')'))
					throw new TemplateException(data.srcCode,"invalid syntax in for statement, for statement must end with a [)]");
				// ex block
				statement(data,body,CTX_FOR);
				
				// performance improvment in special constellation
				/*if(isLoopConform(data.factory,left,cont,update,body,line,data.srcCode.getPosition(),id)!=null) {
					
				}*/
				
				return new For(data.factory,left,cont,update,body,line,data.srcCode.getPosition(),id);					
			}
		// middle foreach
			else if(data.srcCode.forwardIfCurrent("in")) {
				// condition
					comments(data);
					Expression value = expression(data);
					comments(data);
				if(!data.srcCode.forwardIfCurrent(')'))
					throw new TemplateException(data.srcCode,"invalid syntax in for statement, for statement must end with a [)]");
				
				// ex block
				statement(data,body,CTX_FOR);
				if(!(left instanceof Variable))
					throw new TemplateException(data.srcCode,"invalid syntax in for statement, left value is invalid");
				
				//if(!(value instanceof Variable))
				//	throw new TemplateException(data.srcCode,"invalid syntax in for statement, right value is invalid");
				return new ForEach((Variable)left,value,body,line,data.srcCode.getPosition(),id);	
			}
			else 
				throw new TemplateException(data.srcCode,"invalid syntax in for statement");
	}
	
	private TagLoop isLoopConform(Factory factory, Expression left, Expression middle, Expression right,
			Body body, Position start, Position end, String label) {
		print.e(".........................................");
		
		if(!(left instanceof Assign)) return null;
		print.e("left:"+left.getClass().getName());
		Assign l=(Assign) left;
		
		if(!(middle instanceof OPDecision)) return null;
		print.e("middle:"+middle.getClass().getName());
		OPDecision m=(OPDecision) middle;
		print.e(m.getOperation());
		if(m.getOperation()!=OPDecision.LT && m.getOperation()!=OPDecision.LTE) return null;
		
		if(!(right instanceof Assign)) return null;
		print.e("right:"+right.getClass().getName());
		Assign r=(Assign) right;
		if(!(r.getValue() instanceof OpDouble)) return null;
		OpDouble v=(OpDouble) r.getValue();
		if(!(v.getLeft() instanceof Variable)) return null;
		
		// is it i=i+x;
		String var=null;
		try {
			var=VariableString.variableToString(r.getVariable(),false);
			if(!var.equals(VariableString.variableToString((Variable)v.getLeft(),false))) return null;
			
			print.e("->"+var);
			print.e("->"+VariableString.variableToString((Variable)v.getLeft(),false));
		}
		catch (TransformerException e) {
			return null;
		}
		
		if(!(v.getRight() instanceof LitDouble)) return null;
		print.e("**");
		LitDouble vr=(LitDouble) v.getRight();
		print.e("***"+vr.getDoubleValue());
		TagLoop tl=new TagLoop(factory, start, end);
		tl.setBody(body);
		// id
		tl.addAttribute(new Attribute(false, "id",
				factory.createLitString(var,r.getVariable().getStart(),r.getVariable().getEnd()), "string")
		);
		// from
		
		
		
		//addAttribute(new Attribute(false, "name",bc.getFactory().createLitString("thread"+RandomUtil.createRandomStringLC(20)), "string"));
		
		
		
		print.e(r.getVariable());
		print.e(r.getValue());
		
		return tl;
	}

	/**
	 * Liest ein function Statement ein.
	 * <br />
	 * EBNF:<br />
	 * <code>identifier spaces "(" spaces identifier spaces {"," spaces identifier spaces} ")" spaces block;</code>
	 * @return function Statement
	 * @throws TemplateException
	 */
	private final Statement funcStatement(ExprData data,Body parent) throws TemplateException {
		int pos=data.srcCode.getPos();
		
		// read 5 tokens (returntype,access modifier,"abstract|final|static","function", function name)
		String str=variableDec(data, false);
		// if there is no token at all we have no function
		if(str==null) {
			data.srcCode.setPos(pos);
			return null;
		}
		comments(data);
		String[] tokens=new String[]{str,null,null,null,null};
		
		tokens[1]=variableDec(data, false);
		comments(data);
		if(tokens[1]!=null){
			tokens[2]=variableDec(data, false);
			comments(data);
			if(tokens[2]!=null){
{'fraction_non_alphanumeric': 0.13634120828152446, 'fraction_numerical': 0.0015394635561608147, 'mean_word_length': 4.549008870879422, 'pattern_counts': {'":': 0, '<': 85, '<?xml version=': 0, '>': 87, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5147541', 'n_tokens_mistral': 17821, 'n_tokens_neox': 15643, 'n_words': 3220}