<commit_before>package railo.runtime.functions.system;

import java.io.File;
import java.util.Map;

import org.apache.commons.collections.ReferenceMap;

import railo.runtime.Mapping;
import railo.runtime.Page;
import railo.runtime.PageContext;
import railo.runtime.PageSourceImpl;
import railo.runtime.config.ConfigWebImpl;
import railo.runtime.exp.ExpressionException;
import railo.runtime.exp.PageException;
import railo.runtime.op.Caster;
import railo.runtime.type.Collection;
import railo.runtime.type.FunctionValue;
import railo.runtime.type.KeyImpl;
import railo.runtime.type.Struct;
import railo.runtime.type.StructImpl;
import railo.runtime.type.UDF;
import railo.runtime.type.scope.Variables;
import railo.runtime.type.scope.VariablesImpl;
import railo.runtime.type.util.ArrayUtil;

public class CFFunction {
	
	
	private static final Variables VAR = new VariablesImpl();
	private static Map udfs=new ReferenceMap();
	
	
	
	public static Object call(PageContext pc , Object[] objArr) throws PageException {
		if(objArr.length<3)
			throw new ExpressionException("invalid call of a CFML Based Build in Function");
		
		// translate arguments
		String filename=Caster.toString((((FunctionValue) objArr[0]).getValue()));
		Collection.Key name=KeyImpl.toKey((((FunctionValue) objArr[1]).getValue()));
		boolean isweb=Caster.toBooleanValue((((FunctionValue) objArr[2]).getValue()));
		
		Struct namedArguments=null;
		Object[] arguments=null;
		if(objArr.length<=3)arguments=ArrayUtil.OBJECT_EMPTY;
		else if(objArr[3] instanceof FunctionValue){
			FunctionValue fv;
			namedArguments=new StructImpl();
			for(int i=3;i<objArr.length;i++){
				fv=toFunctionValue(name,objArr[i]);
				namedArguments.set(fv.getName(), fv.getValue());
			}
		}
		else {
			arguments=new Object[objArr.length-3];
			for(int i=3;i<objArr.length;i++){
				arguments[i-3]=toObject(name,objArr[i]);
			}
		}
		
		
		// load UDF
		UDF udf=loadUDF(pc, filename, name, isweb);
		
		// execute UDF
		if(namedArguments==null)return udf.call(pc, arguments, false);
		return udf.callWithNamedValues(pc, namedArguments, false);
	}

	public static synchronized UDF loadUDF(PageContext pc, String filename,Collection.Key name,boolean isweb) throws PageException {
		ConfigWebImpl config = (ConfigWebImpl) pc.getConfig();
		String key=isweb?name.getString()+config.getId():name.getString();
    	UDF udf=(UDF) udfs.get(key);
		if(udf!=null) return udf;
		
		
		Mapping mapping=isweb?config.getFunctionMapping():config.getServerFunctionMapping();
    	PageSourceImpl ps = (PageSourceImpl) mapping.getPageSource(filename);
    	Page p = ps.loadPage(pc,pc.getConfig());	
		
    	
    	// execute page
    	Variables old = pc.variablesScope();
    	pc.setVariablesScope(VAR);
    	boolean wasSilent = pc.setSilent();
    	try {
			p.call(pc);
			Object o= pc.variablesScope().get(name,null);
			if(o instanceof UDF) {
				udf= (UDF) o;
				udfs.put(key, udf);
				return udf;
			}
			throw new ExpressionException("there is no Function defined with name ["+name+"] in template ["+mapping.getStrPhysical()+File.separator+filename+"]");
		} 
    	catch (Throwable t) {
			throw Caster.toPageException(t);
		}
		finally{
			pc.setVariablesScope(old);
			if(!wasSilent)pc.unsetSilent();
		}
		
		
	}

	private static FunctionValue toFunctionValue(Collection.Key name,Object obj) throws ExpressionException {
		if(obj instanceof FunctionValue)
			return (FunctionValue) obj;
		throw new ExpressionException("invalid argument for function "+name+", you can not mix named and unnamed arguments");
	}

	private static Object toObject(Collection.Key name,Object obj) throws ExpressionException {
		if(obj instanceof FunctionValue)
			throw new ExpressionException("invalid argument for function "+name+", you can not mix named and unnamed arguments");
		return obj;
	}<commit_msg>solved ticket https://issues.jboss.org/browse/RAILO-1185<commit_after>package railo.runtime.functions.system;

import java.io.File;

import railo.runtime.Mapping;
import railo.runtime.Page;
import railo.runtime.PageContext;
import railo.runtime.PageSourceImpl;
import railo.runtime.config.ConfigWebImpl;
import railo.runtime.exp.ExpressionException;
import railo.runtime.exp.PageException;
import railo.runtime.op.Caster;
import railo.runtime.type.Collection;
import railo.runtime.type.FunctionValue;
import railo.runtime.type.KeyImpl;
import railo.runtime.type.Struct;
import railo.runtime.type.StructImpl;
import railo.runtime.type.UDF;
import railo.runtime.type.scope.Variables;
import railo.runtime.type.scope.VariablesImpl;
import railo.runtime.type.util.ArrayUtil;

public class CFFunction {
	
	
	private static final Variables VAR = new VariablesImpl();
	private static final Collection.Key CALLER = KeyImpl.init("caller");
	//private static Map udfs=new ReferenceMap();
	
	public static Object call(PageContext pc , Object[] objArr) throws PageException {
		if(objArr.length<3)
			throw new ExpressionException("invalid call of a CFML Based Build in Function");
		
		// translate arguments
		String filename=Caster.toString((((FunctionValue) objArr[0]).getValue()));
		Collection.Key name=KeyImpl.toKey((((FunctionValue) objArr[1]).getValue()));
		boolean isweb=Caster.toBooleanValue((((FunctionValue) objArr[2]).getValue()));
		
		
		UDF udf=loadUDF(pc, filename, name, isweb);
		Struct meta = udf.getMetaData(pc);
		boolean caller=meta==null?false:Caster.toBooleanValue(meta.get(CALLER,Boolean.FALSE),false);
		
		Struct namedArguments=null;
		Object[] arguments=null;
		if(objArr.length<=3)arguments=ArrayUtil.OBJECT_EMPTY;
		else if(objArr[3] instanceof FunctionValue){
			FunctionValue fv;
			namedArguments=new StructImpl();
			if(caller)namedArguments.setEL(CALLER, pc.undefinedScope().duplicate(false));
			for(int i=3;i<objArr.length;i++){
				fv=toFunctionValue(name,objArr[i]);
				namedArguments.set(fv.getName(), fv.getValue());
			}
		}
		else {
			int offset=(caller?2:3);
			arguments=new Object[objArr.length-offset];
			if(caller)arguments[0]=pc.undefinedScope().duplicate(false);
			for(int i=3;i<objArr.length;i++){
				arguments[i-offset]=toObject(name,objArr[i]);
			}
		}
		
		
		// load UDF
		
		
		// execute UDF
		if(namedArguments==null){
			return udf.call(pc, arguments, false);
		}
		
		
		return udf.callWithNamedValues(pc, namedArguments, false);
	}

	public static synchronized UDF loadUDF(PageContext pc, String filename,Collection.Key name,boolean isweb) throws PageException {
		ConfigWebImpl config = (ConfigWebImpl) pc.getConfig();
		String key=isweb?name.getString()+config.getId():name.getString();
    	UDF udf=config.getFromFunctionCache(key);
		if(udf!=null) return udf;
		
		Mapping mapping=isweb?config.getFunctionMapping():config.getServerFunctionMapping();
    	PageSourceImpl ps = (PageSourceImpl) mapping.getPageSource(filename);
    	Page p = ps.loadPage(pc,pc.getConfig());	
		
    	
    	// execute page
    	Variables old = pc.variablesScope();
    	pc.setVariablesScope(VAR);
    	boolean wasSilent = pc.setSilent();
    	try {
			p.call(pc);
			Object o= pc.variablesScope().get(name,null);
			if(o instanceof UDF) {
				udf= (UDF) o;
				config.putToFunctionCache(key, udf);
				return udf;
			}
			throw new ExpressionException("there is no Function defined with name ["+name+"] in template ["+mapping.getStrPhysical()+File.separator+filename+"]");
		} 
    	catch (Throwable t) {
			throw Caster.toPageException(t);
		}
		finally{
			pc.setVariablesScope(old);
			if(!wasSilent)pc.unsetSilent();
		}
		
		
	}

	private static FunctionValue toFunctionValue(Collection.Key name,Object obj) throws ExpressionException {
		if(obj instanceof FunctionValue)
			return (FunctionValue) obj;
		throw new ExpressionException("invalid argument for function "+name+", you can not mix named and unnamed arguments");
	}

	private static Object toObject(Collection.Key name,Object obj) throws ExpressionException {
		if(obj instanceof FunctionValue)
			throw new ExpressionException("invalid argument for function "+name+", you can not mix named and unnamed arguments");
		return obj;
	}
{'fraction_non_alphanumeric': 0.12323507555115185, 'fraction_numerical': 0.003096358682189745, 'mean_word_length': 4.894160583941606, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 3, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, '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': '5045706', 'n_tokens_mistral': 2755, 'n_tokens_neox': 2480, 'n_words': 544}