/** * Adds a local function. * * @param fun function instance * @param ii input info * @return function id * @throws QueryException query exception */ public int add(final UserFunc fun, final InputInfo ii) throws QueryException { final QNm name = fun.name; final byte[] uri = name.uri(); if (uri.length == 0) FUNNONS.thrw(ii, name.string()); if (NSGlobal.standard(uri)) { if (fun.declared) NAMERES.thrw(ii, name.string()); funError(name, ii); } final byte[] ln = name.local(); for (int l = 0; l < func.length; ++l) { final QNm qn = func[l].name; final byte[] u = qn.uri(); final byte[] nm = qn.local(); if (eq(ln, nm) && eq(uri, u) && fun.args.length == func[l].args.length) { // declare function that has been called before if (!func[l].declared) { func[l] = fun; return l; } // duplicate declaration FUNCDEFINED.thrw(ii, fun); } } // add function skeleton func = Array.add(func, fun); calls = Array.add(calls, new UserFuncCall[0]); return func.length - 1; }
/** * Finds similar function names and throws an error message. * * @param name function name * @param ii input info * @throws QueryException query exception */ public void funError(final QNm name, final InputInfo ii) throws QueryException { // find global function Functions.get().error(name, ii); // find similar local function final Levenshtein ls = new Levenshtein(); final byte[] nm = lc(name.local()); for (int n = 0; n < func.length; ++n) { if (ls.similar(nm, lc(func[n].name.local()), 0)) { FUNSIMILAR.thrw(ii, name.string(), func[n].name.string()); } } }
/** * Returns the specified function. * * @param name name of the function * @param args optional arguments * @param dyn compile-/run-time flag * @param ctx query context * @param ii input info * @return function instance * @throws QueryException query exception */ public TypedFunc get( final QNm name, final Expr[] args, final boolean dyn, final QueryContext ctx, final InputInfo ii) throws QueryException { // find function final byte[] uri = name.uri(); final byte[] ln = name.local(); // parse data type constructors if (eq(uri, XSURI)) { final Type type = AtomType.find(name, true); if (type == null || type == AtomType.NOT || type == AtomType.AAT) { final Levenshtein ls = new Levenshtein(); for (final AtomType t : AtomType.values()) { if (t.par != null && ls.similar(lc(ln), lc(t.string()), 0)) FUNSIMILAR.thrw(ii, name.string(), t.string()); } FUNCUNKNOWN.thrw(ii, name.string()); } if (args.length != 1) FUNCTYPE.thrw(ii, name.string()); final SeqType to = SeqType.get(type, SeqType.Occ.ZO); return TypedFunc.constr(new Cast(ii, args[0], to), to); } // check Java functions - only allowed with administrator permissions if (startsWith(uri, JAVAPRE) && ctx.context.user.perm(User.ADMIN)) { final String c = string(substring(uri, JAVAPRE.length)); // convert dashes to upper-case initials final TokenBuilder tb = new TokenBuilder().add(c).add('.'); boolean dash = false; for (int p = 0; p < ln.length; p += cl(ln, p)) { final int ch = cp(ln, p); if (dash) { tb.add(Character.toUpperCase(ch)); dash = false; } else { dash = ch == '-'; if (!dash) tb.add(ch); } } final String java = tb.toString(); final int i = java.lastIndexOf("."); final Class<?> cls = Reflect.find(java.substring(0, i)); if (cls == null) FUNCJAVA.thrw(ii, java); final String mth = java.substring(i + 1); return TypedFunc.java(new JavaFunc(ii, cls, mth, args)); } // check predefined functions final FuncCall fun = Functions.get().get(ln, uri, args, ctx, ii); if (fun != null) { for (final Function f : Function.UPDATING) { if (fun.def == f) { ctx.updating = true; break; } } return new TypedFunc(fun, fun.def.type(args.length)); } // find local function for (int l = 0; l < func.length; ++l) { final QNm qn = func[l].name; if (eq(ln, qn.local()) && eq(uri, qn.uri()) && args.length == func[l].args.length) return new TypedFunc(add(ii, qn, l, args), FuncType.get(func[l])); } // add function call for function that has not been defined yet if (!dyn && Types.find(name, false) == null) { return new TypedFunc( add(ii, name, add(new UserFunc(ii, name, new Var[args.length], null, false), ii), args), FuncType.arity(args.length)); } return null; }