use of lucee.transformer.library.function.FunctionLibFunctionArg in project Lucee by lucee.
the class VT method _writeOutFirstBIF.
static Type _writeOutFirstBIF(BytecodeContext bc, BIF bif, int mode, boolean last, Position line) throws TransformerException {
double start = SystemUtil.millis();
GeneratorAdapter adapter = bc.getAdapter();
adapter.loadArg(0);
// class
ClassDefinition bifCD = bif.getClassDefinition();
Class clazz = null;
try {
clazz = bifCD.getClazz();
} catch (Exception e) {
SystemOut.printDate(e);
}
Type rtnType = Types.toType(bif.getReturnType());
if (rtnType == Types.VOID)
rtnType = Types.STRING;
// arguments
Argument[] args = bif.getArguments();
Type[] argTypes;
// MUST setting this to false need to work !!!
boolean core = bif.getFlf().isCore();
if (bif.getArgType() == FunctionLibFunction.ARG_FIX && !bifCD.isBundle() && core) {
if (isNamed(bif.getFlf().getName(), args)) {
NamedArgument[] nargs = toNamedArguments(args);
String[] names = new String[nargs.length];
// get all names
for (int i = 0; i < nargs.length; i++) {
names[i] = getName(nargs[i].getName());
}
ArrayList<FunctionLibFunctionArg> list = bif.getFlf().getArg();
Iterator<FunctionLibFunctionArg> it = list.iterator();
argTypes = new Type[list.size() + 1];
argTypes[0] = Types.PAGE_CONTEXT;
FunctionLibFunctionArg flfa;
int index = 0;
VT vt;
while (it.hasNext()) {
flfa = it.next();
vt = getMatchingValueAndType(bc.getFactory(), flfa, nargs, names, line);
if (vt.index != -1)
names[vt.index] = null;
argTypes[++index] = Types.toType(vt.type);
if (vt.value == null)
ASMConstants.NULL(bc.getAdapter());
else
vt.value.writeOut(bc, Types.isPrimitiveType(argTypes[index]) ? MODE_VALUE : MODE_REF);
}
for (int y = 0; y < names.length; y++) {
if (names[y] != null) {
TransformerException bce = new TransformerException("argument [" + names[y] + "] is not allowed for function [" + bif.getFlf().getName() + "]", args[y].getStart());
UDFUtil.addFunctionDoc(bce, bif.getFlf());
throw bce;
}
}
} else {
argTypes = new Type[args.length + 1];
argTypes[0] = Types.PAGE_CONTEXT;
for (int y = 0; y < args.length; y++) {
argTypes[y + 1] = Types.toType(args[y].getStringType());
args[y].writeOutValue(bc, Types.isPrimitiveType(argTypes[y + 1]) ? MODE_VALUE : MODE_REF);
}
// if no method exists for the exact match of arguments, call the method with all arguments (when exists)
if (methodExists(clazz, "call", argTypes, rtnType) == Boolean.FALSE) {
ArrayList<FunctionLibFunctionArg> _args = bif.getFlf().getArg();
Type[] tmp = new Type[_args.size() + 1];
// fill the existing
for (int i = 0; i < argTypes.length; i++) {
tmp[i] = argTypes[i];
}
// get the rest with default values
FunctionLibFunctionArg flfa;
VT def;
for (int i = argTypes.length; i < tmp.length; i++) {
flfa = _args.get(i - 1);
tmp[i] = Types.toType(flfa.getTypeAsString());
def = getDefaultValue(bc.getFactory(), flfa);
if (def.value != null)
def.value.writeOut(bc, Types.isPrimitiveType(tmp[i]) ? MODE_VALUE : MODE_REF);
else
ASMConstants.NULL(bc.getAdapter());
}
argTypes = tmp;
}
}
} else // Arg Type DYN or bundle based
{
// /////////////////////////////////////////////////////////////
if (bif.getArgType() == FunctionLibFunction.ARG_FIX) {
if (isNamed(bif.getFlf().getName(), args)) {
NamedArgument[] nargs = toNamedArguments(args);
String[] names = getNames(nargs);
ArrayList<FunctionLibFunctionArg> list = bif.getFlf().getArg();
Iterator<FunctionLibFunctionArg> it = list.iterator();
LinkedList<Argument> tmpArgs = new LinkedList<Argument>();
LinkedList<Boolean> nulls = new LinkedList<Boolean>();
FunctionLibFunctionArg flfa;
VT vt;
while (it.hasNext()) {
flfa = it.next();
vt = getMatchingValueAndType(bc.getFactory(), flfa, nargs, names, line);
if (vt.index != -1)
names[vt.index] = null;
if (vt.value == null)
// has to by any otherwise a caster is set
tmpArgs.add(new Argument(bif.getFactory().createNull(), "any"));
else
tmpArgs.add(new Argument(vt.value, vt.type));
nulls.add(vt.value == null);
}
for (int y = 0; y < names.length; y++) {
if (names[y] != null) {
TransformerException bce = new TransformerException("argument [" + names[y] + "] is not allowed for function [" + bif.getFlf().getName() + "]", args[y].getStart());
UDFUtil.addFunctionDoc(bce, bif.getFlf());
throw bce;
}
}
// remove null at the end
Boolean tmp;
while ((tmp = nulls.pollLast()) != null) {
if (!tmp.booleanValue())
break;
tmpArgs.pollLast();
}
args = tmpArgs.toArray(new Argument[tmpArgs.size()]);
}
}
// /////////////////////////////////////////////////////////////
argTypes = new Type[2];
argTypes[0] = Types.PAGE_CONTEXT;
argTypes[1] = Types.OBJECT_ARRAY;
ExpressionUtil.writeOutExpressionArray(bc, Types.OBJECT, args);
}
// core
if (core && !bifCD.isBundle()) {
adapter.invokeStatic(Type.getType(clazz), new Method("call", rtnType, argTypes));
} else // external
{
// className
if (bifCD.getClassName() != null)
adapter.push(bifCD.getClassName());
else
ASMConstants.NULL(adapter);
if (// bundle name
bifCD.getName() != null)
// bundle name
adapter.push(bifCD.getName());
else
ASMConstants.NULL(adapter);
if (// bundle version
bifCD.getVersionAsString() != null)
// bundle version
adapter.push(bifCD.getVersionAsString());
else
ASMConstants.NULL(adapter);
adapter.invokeStatic(Types.FUNCTION_HANDLER_POOL, INVOKE);
rtnType = Types.OBJECT;
}
if (mode == MODE_REF || !last) {
if (Types.isPrimitiveType(rtnType)) {
adapter.invokeStatic(Types.CASTER, new Method("toRef", Types.toRefType(rtnType), new Type[] { rtnType }));
rtnType = Types.toRefType(rtnType);
}
}
return rtnType;
}
use of lucee.transformer.library.function.FunctionLibFunctionArg in project Lucee by lucee.
the class AbstrCFMLExprTransformer method getFunctionMember.
/**
* Liest die Argumente eines Funktonsaufruf ein und prueft ob die Funktion
* innerhalb der FLD (Function Library Descriptor) definiert ist.
* Falls sie existiert wird die Funktion gegen diese geprueft und ein build-in-function CFXD Element generiert,
* ansonsten ein normales funcion-call Element.
* <br />
* EBNF:<br />
* <code>[impOp{"," impOp}];</code>
* @param name Identifier der Funktion als Zeichenkette
* @param checkLibrary Soll geprueft werden ob die Funktion innerhalb der Library existiert.
* @return CFXD Element
* @throws TemplateException
*/
private FunctionMember getFunctionMember(ExprData data, final ExprString name, boolean checkLibrary) throws TemplateException {
// get Function Library
checkLibrary = checkLibrary && data.flibs != null;
FunctionLibFunction flf = null;
if (checkLibrary) {
if (!(name instanceof Literal))
// should never happen!
throw new TemplateException(data.srcCode, "syntax error");
for (int i = 0; i < data.flibs.length; i++) {
flf = data.flibs[i].getFunction(((Literal) name).getString());
if (flf != null)
break;
}
if (flf == null) {
checkLibrary = false;
}
}
FunctionMember fm = null;
while (true) {
int pos = data.srcCode.getPos();
// Element Function
if (checkLibrary) {
BIF bif = new BIF(data.factory, data.settings, flf);
// TODO data.ep.add(flf, bif, data.srcCode);
bif.setArgType(flf.getArgType());
try {
bif.setClassDefinition(flf.getFunctionClassDefinition());
} catch (Throwable t) {
ExceptionUtil.rethrowIfNecessary(t);
throw new PageRuntimeException(t);
}
bif.setReturnType(flf.getReturnTypeAsString());
fm = bif;
if (flf.getArgType() == FunctionLibFunction.ARG_DYNAMIC && flf.hasDefaultValues()) {
ArrayList<FunctionLibFunctionArg> args = flf.getArg();
Iterator<FunctionLibFunctionArg> it = args.iterator();
FunctionLibFunctionArg arg;
while (it.hasNext()) {
arg = it.next();
if (arg.getDefaultValue() != null)
bif.addArgument(new NamedArgument(data.factory.createLitString(arg.getName()), data.factory.createLitString(arg.getDefaultValue()), arg.getTypeAsString(), false));
}
}
} else {
fm = new UDF(name);
}
int count = getFunctionMemberAttrs(data, name, checkLibrary, fm, flf);
if (checkLibrary) {
// pre
if (flf.hasTteClass()) {
FunctionLibFunction tmp = flf.getEvaluator().pre((BIF) fm, flf);
if (tmp != null && tmp != flf) {
flf = tmp;
data.srcCode.setPos(pos);
continue;
}
}
// check max attributes
{
boolean isDynamic = flf.getArgType() == FunctionLibFunction.ARG_DYNAMIC;
int max = flf.getArgMax();
// Dynamic
if (isDynamic) {
if (max != -1 && max < fm.getArguments().length)
throw new TemplateException(data.srcCode, "too many Attributes (" + max + ":" + fm.getArguments().length + ") in function [ " + ASMUtil.display(name) + " ]");
} else // Fix
{
if (flf.getArg().size() < fm.getArguments().length) {
TemplateException te = new TemplateException(data.srcCode, "too many Attributes (" + flf.getArg().size() + ":" + fm.getArguments().length + ") in function call [" + ASMUtil.display(name) + "]");
UDFUtil.addFunctionDoc(te, flf);
throw te;
}
}
}
// check min attributes
if (flf.getArgMin() > count) {
TemplateException te = new TemplateException(data.srcCode, "too few attributes in function [" + ASMUtil.display(name) + "]");
if (flf.getArgType() == FunctionLibFunction.ARG_FIX)
UDFUtil.addFunctionDoc(te, flf);
throw te;
}
// evaluator
if (flf.hasTteClass()) {
flf.getEvaluator().execute((BIF) fm, flf);
}
}
comments(data);
if (checkLibrary)
data.ep.add(flf, (BIF) fm, data.srcCode);
break;
}
return fm;
}
use of lucee.transformer.library.function.FunctionLibFunctionArg in project Lucee by lucee.
the class CFMLExpressionInterpreter method functionArg.
/**
* Liest die Argumente eines Funktonsaufruf ein und prueft ob die Funktion
* innerhalb der FLD (Function Library Descriptor) definiert ist.
* Falls sie existiert wird die Funktion gegen diese geprueft und ein build-in-function CFXD Element generiert,
* ansonsten ein normales funcion-call Element.
* <br />
* EBNF:<br />
* <code>[impOp{"," impOp}];</code>
* @param name Identifier der Funktion als Zeichenkette
* @param checkLibrary Soll geprueft werden ob die Funktion innerhalb der Library existiert.
* @param flf FLD Function definition .
* @return CFXD Element
* @throws PageException
*/
private Ref[] functionArg(String name, boolean checkLibrary, FunctionLibFunction flf, char end) throws PageException {
// get Function Library
checkLibrary = checkLibrary && flf != null;
// Function Attributes
List<Ref> arr = new ArrayList<Ref>();
List<FunctionLibFunctionArg> arrFuncLibAtt = null;
int libLen = 0;
if (checkLibrary) {
arrFuncLibAtt = flf.getArg();
libLen = arrFuncLibAtt.size();
}
int count = 0;
Ref ref;
do {
cfml.next();
cfml.removeSpace();
// finish
if (cfml.isCurrent(end))
break;
// too many Attributes
boolean isDynamic = false;
int max = -1;
if (checkLibrary) {
isDynamic = isDynamic(flf);
max = flf.getArgMax();
// Dynamic
if (isDynamic) {
if (max != -1 && max <= count)
throw new InterpreterException("too many Attributes in function [" + name + "]");
} else // Fix
{
if (libLen <= count)
throw new InterpreterException("too many Attributes in function [" + name + "]");
}
}
if (checkLibrary && !isDynamic) {
// current attribues from library
FunctionLibFunctionArg funcLibAtt = (FunctionLibFunctionArg) arrFuncLibAtt.get(count);
short type = CFTypes.toShort(funcLibAtt.getTypeAsString(), false, CFTypes.TYPE_UNKNOW);
if (type == CFTypes.TYPE_VARIABLE_STRING) {
arr.add(functionArgDeclarationVarString());
} else {
ref = functionArgDeclaration();
arr.add(new Casting(funcLibAtt.getTypeAsString(), type, ref));
}
} else {
arr.add(functionArgDeclaration());
}
cfml.removeSpace();
count++;
} while (cfml.isCurrent(','));
// end with ) ??
if (!cfml.forwardIfCurrent(end)) {
if (name.startsWith("_json"))
throw new InterpreterException("Invalid Syntax Closing [" + end + "] not found");
throw new InterpreterException("Invalid Syntax Closing [" + end + "] for function [" + name + "] not found");
}
// check min attributes
if (checkLibrary && flf.getArgMin() > count)
throw new InterpreterException("to less Attributes in function [" + name + "]");
cfml.removeSpace();
return (Ref[]) arr.toArray(new Ref[arr.size()]);
}
use of lucee.transformer.library.function.FunctionLibFunctionArg in project Lucee by lucee.
the class GetFunctionData method cfmlBasedFunction.
private static Struct cfmlBasedFunction(PageContext pc, FunctionLibFunction function) throws PageException {
Struct sct = new StructImpl();
ArrayList<FunctionLibFunctionArg> args = function.getArg();
String filename = Caster.toString(args.get(0).getDefaultValue());
Key name = KeyImpl.toKey(args.get(1).getDefaultValue());
boolean isWeb = Caster.toBooleanValue(args.get(2).getDefaultValue());
UDF udf = CFFunction.loadUDF(pc, filename, name, isWeb);
sct.set(KeyConstants._name, function.getName());
sct.set(ARGUMENT_TYPE, "fixed");
sct.set(KeyConstants._description, StringUtil.emptyIfNull(udf.getHint()));
sct.set(RETURN_TYPE, StringUtil.emptyIfNull(udf.getReturnTypeAsString()));
sct.set(KeyConstants._type, "cfml");
sct.set(SOURCE, udf.getSource());
sct.set(KeyConstants._status, "implemeted");
FunctionArgument[] fas = udf.getFunctionArguments();
Array _args = new ArrayImpl();
sct.set(KeyConstants._arguments, _args);
int min = 0, max = 0;
for (int i = 0; i < fas.length; i++) {
FunctionArgument fa = fas[i];
Struct meta = fa.getMetaData();
Struct _arg = new StructImpl();
if (fa.isRequired())
min++;
max++;
_arg.set(KeyConstants._required, fa.isRequired() ? Boolean.TRUE : Boolean.FALSE);
_arg.set(KeyConstants._type, StringUtil.emptyIfNull(fa.getTypeAsString()));
_arg.set(KeyConstants._name, StringUtil.emptyIfNull(fa.getName()));
_arg.set(KeyConstants._description, StringUtil.emptyIfNull(fa.getHint()));
String status;
if (meta == null)
status = "implemeted";
else
status = TagLibFactory.toStatus(TagLibFactory.toStatus(Caster.toString(meta.get(KeyConstants._status, "implemeted"))));
_arg.set(KeyConstants._status, status);
_args.append(_arg);
}
sct.set(ARG_MIN, Caster.toDouble(min));
sct.set(ARG_MAX, Caster.toDouble(max));
return sct;
}
use of lucee.transformer.library.function.FunctionLibFunctionArg in project Lucee by lucee.
the class MemberUtil method callWithNamedValues.
public static Object callWithNamedValues(PageContext pc, Object coll, Collection.Key methodName, Struct args, short type, String strType) throws PageException {
Map<Key, FunctionLibFunction> members = getMembers(pc, type);
FunctionLibFunction member = members.get(methodName);
if (member != null) {
List<FunctionLibFunctionArg> _args = member.getArg();
FunctionLibFunctionArg arg;
if (args.size() < _args.size()) {
Object val;
ArrayList<Ref> refs = new ArrayList<Ref>();
arg = _args.get(0);
refs.add(new Casting(arg.getTypeAsString(), arg.getType(), new LFunctionValue(new LString(arg.getName()), coll)));
for (int y = 1; y < _args.size(); y++) {
arg = _args.get(y);
// match by name
val = args.get(arg.getName(), null);
// match by alias
if (val == null) {
String alias = arg.getAlias();
if (!StringUtil.isEmpty(alias, true)) {
String[] aliases = lucee.runtime.type.util.ListUtil.trimItems(lucee.runtime.type.util.ListUtil.listToStringArray(alias, ','));
for (int x = 0; x < aliases.length; x++) {
val = args.get(aliases[x], null);
if (val != null)
break;
}
}
}
if (val == null) {
if (arg.getRequired()) {
String[] names = member.getMemberNames();
String n = ArrayUtil.isEmpty(names) ? "" : names[0];
throw new ExpressionException("missing required argument [" + arg.getName() + "] for member function call [" + n + "]");
}
} else {
refs.add(new Casting(arg.getTypeAsString(), arg.getType(), new LFunctionValue(new LString(arg.getName()), val)));
// refs.add(new LFunctionValue(new LString(arg.getName()),new Casting(pc,arg.getTypeAsString(),arg.getType(),val)));
}
}
return new BIFCall(coll, member, refs.toArray(new Ref[refs.size()])).getValue(pc);
}
}
throw new ExpressionException("No matching function member [" + methodName + "] for call with named arguments found, available function members are [" + lucee.runtime.type.util.ListUtil.sort(CollectionUtil.getKeyList(members.keySet().iterator(), ","), "textnocase", "asc", ",") + "]");
}
Aggregations