package org.geogebra.common.kernel.parser.cashandlers; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.TreeSet; import org.geogebra.common.main.Localization; import org.geogebra.common.plugin.Operation; import org.geogebra.common.util.lang.Unicode; /** * Handles function references for Parser * * @author zbynek * */ public class ParserFunctions { private final List<Map<String, Operation>> stringToOp = new ArrayList<Map<String, Operation>>(); private final TreeSet<String> RESERVED_FUNCTION_NAMES = new TreeSet<String>(); private final TreeSet<String> syntaxes = new TreeSet<String>(); private static final int MAX_ARGS = 4; private boolean localeLoaded = false; private boolean inverseTrig; /** * Initializes the string => operation map and reserved names set */ public ParserFunctions() { for (int i = 0; i <= MAX_ARGS; i++) { stringToOp.add(new TreeMap<String, Operation>()); } reset(); } private void reset() { RESERVED_FUNCTION_NAMES.clear(); syntaxes.clear(); for (int i = 0; i <= MAX_ARGS; i++) { stringToOp.get(i).clear(); } put(1, "sin", Operation.SIN); put(1, "Sin", Operation.SIN, null); put(1, "cos", Operation.COS); put(1, "Cos", Operation.COS, null); put(1, "tan", Operation.TAN); put(1, "Tan", Operation.TAN, null); put(1, "csc", Operation.CSC); put(1, "Csc", Operation.CSC, null); put(1, "cosec", Operation.CSC); put(1, "Cosec", Operation.CSC, null); put(1, "sec", Operation.SEC); put(1, "Sec", Operation.SEC, null); put(1, "cot", Operation.COT); put(1, "Cot", Operation.COT, null); put(1, "cotan", Operation.COT); put(1, "Cotan", Operation.COT, null); put(1, "ctg", Operation.COT); put(1, "Ctg", Operation.COT, null); put(1, "sinh", Operation.SINH); put(1, "Sinh", Operation.SINH, null); put(1, "cosh", Operation.COSH); put(1, "Cosh", Operation.COSH, null); put(1, "tanh", Operation.TANH); put(1, "Tanh", Operation.TANH, null); put(1, "csch", Operation.CSCH); put(1, "Csch", Operation.CSCH, null); put(1, "cosech", Operation.CSCH); put(1, "Cosech", Operation.CSCH, null); put(1, "sech", Operation.SECH); put(1, "Sech", Operation.SECH, null); put(1, "coth", Operation.COTH); put(1, "Coth", Operation.COTH, null); put(1, "cotanh", Operation.COTH); put(1, "Cotanh", Operation.COTH, null); put(1, "ctgh", Operation.COTH); put(1, "Ctgh", Operation.COTH, null); put(1, "asind", Operation.ARCSIND); put(1, "arcsind", Operation.ARCSIND); put(1, "arcSind", Operation.ARCSIND); put(1, "ArcSind", Operation.ARCSIND, null); put(1, "acosd", Operation.ARCCOSD); put(1, "arccosd", Operation.ARCCOSD); put(1, "arcCosd", Operation.ARCCOSD); put(1, "ArcCosd", Operation.ARCCOSD, null); put(1, "atand", Operation.ARCTAND); put(1, "arctand", Operation.ARCTAND); put(1, "arcTand", Operation.ARCTAND); put(1, "ArcTand", Operation.ARCTAND); put(2, "atan2d", Operation.ARCTAN2D, "( <y>, <x> )"); put(2, "arctan2d", Operation.ARCTAN2D, "( <y>, <x> )"); put(2, "arcTan2d", Operation.ARCTAN2D, null); put(2, "ArcTan2d", Operation.ARCTAN2D, null); put(1, "asin", Operation.ARCSIN); put(1, "aSin", Operation.ARCSIN, null); put(1, "Asin", Operation.ARCSIN, null); put(1, "ASin", Operation.ARCSIN, null); put(1, "arcsin", Operation.ARCSIN); put(1, "arcSin", Operation.ARCSIN, null); put(1, "arsin", Operation.ARCSIN, null); put(1, "arSin", Operation.ARCSIN, null); put(1, "Arcsin", Operation.ARCSIN, null); put(1, "ArcSin", Operation.ARCSIN, null); put(1, "Acos", Operation.ARCCOS, null); put(1, "ACos", Operation.ARCCOS, null); put(1, "acos", Operation.ARCCOS); put(1, "aCos", Operation.ARCCOS, null); put(1, "arccos", Operation.ARCCOS); put(1, "arcCos", Operation.ARCCOS, null); put(1, "arcos", Operation.ARCCOS, null); put(1, "arCos", Operation.ARCCOS, null); put(1, "Arccos", Operation.ARCCOS, null); put(1, "ArcCos", Operation.ARCCOS, null); put(1, "atan", Operation.ARCTAN); put(1, "aTan", Operation.ARCTAN, null); put(1, "Atan", Operation.ARCTAN, null); put(1, "ATan", Operation.ARCTAN, null); put(1, "arctan", Operation.ARCTAN); put(1, "arcTan", Operation.ARCTAN, null); put(1, "artan", Operation.ARCTAN, null); put(1, "arTan", Operation.ARCTAN, null); put(1, "Arctan", Operation.ARCTAN, null); put(1, "ArcTan", Operation.ARCTAN, null); put(1, "asinh", Operation.ASINH); put(1, "aSinh", Operation.ASINH, null); put(1, "Asinh", Operation.ASINH, null); put(1, "ASinh", Operation.ASINH, null); put(1, "Arcsinh", Operation.ASINH, null); put(1, "ArcSinh", Operation.ASINH, null); put(1, "arsinh", Operation.ASINH, null); put(1, "arSinh", Operation.ASINH, null); put(1, "arcsinh", Operation.ASINH); put(1, "arcSinh", Operation.ASINH, null); put(1, "acosh", Operation.ACOSH); put(1, "aCosh", Operation.ACOSH, null); put(1, "Acosh", Operation.ACOSH, null); put(1, "ACosh", Operation.ACOSH, null); put(1, "arccosh", Operation.ACOSH); put(1, "arcCosh", Operation.ACOSH, null); put(1, "arcosh", Operation.ACOSH, null); put(1, "arCosh", Operation.ACOSH, null); put(1, "Arccosh", Operation.ACOSH, null); put(1, "ArcCosh", Operation.ACOSH, null); put(1, "arctanh", Operation.ATANH); put(1, "arcTanh", Operation.ATANH, null); put(1, "atanh", Operation.ATANH); put(1, "aTanh", Operation.ATANH, null); put(1, "Atanh", Operation.ATANH, null); put(1, "ATanh", Operation.ATANH, null); put(1, "artanh", Operation.ATANH, null); put(1, "arTanh", Operation.ATANH, null); put(1, "Arctanh", Operation.ATANH, null); put(1, "ArcTanh", Operation.ATANH, null); put(2, "atan2", Operation.ARCTAN2, "( <y>, <x> )"); put(2, "Atan2", Operation.ARCTAN2, null); put(2, "artan2", Operation.ARCTAN2, null); put(2, "arctan2", Operation.ARCTAN2, "( <y>, <x> )"); put(2, "Arctan2", Operation.ARCTAN2, null); put(2, "aTan2", Operation.ARCTAN2, null); put(2, "ATan2", Operation.ARCTAN2, null); put(2, "arTan2", Operation.ARCTAN2, null); put(2, "arcTan2", Operation.ARCTAN2, null); put(2, "ArcTan2", Operation.ARCTAN2, null); put(1, "erf", Operation.ERF); put(1, "Erf", Operation.ERF, null); put(1, "psi", Operation.PSI); put(2, "polygamma", Operation.POLYGAMMA, "( <m>, <x> )"); put(2, "polyGamma", Operation.POLYGAMMA, null); put(2, "PolyGamma", Operation.POLYGAMMA, null); put(1, "exp", Operation.EXP); put(1, "Exp", Operation.EXP, null); put(1, "log", Operation.LOG); put(1, "ln", Operation.LOG); put(1, "Ln", Operation.LOG, null); put(2, "log", Operation.LOGB, "( <b> , <x> )"); put(2, "ln", Operation.LOGB, null); put(2, "Ln", Operation.LOGB, null); put(1, "ld", Operation.LOG2); put(1, "log2", Operation.LOG2); put(1, "lg", Operation.LOG10); put(1, "log10", Operation.LOG10); put(1, "zeta", Operation.ZETA); put(1, "Zeta", Operation.ZETA, null); put(2, "beta", Operation.BETA, "( <a>, <b> )"); put(2, "Beta", Operation.BETA, null); put(3, "beta", Operation.BETA_INCOMPLETE, "( <a>, <b>, <x> )"); put(3, "Beta", Operation.BETA_INCOMPLETE, null); put(3, "betaRegularized", Operation.BETA_INCOMPLETE_REGULARIZED, "( <a>, <b>, <x> )"); put(3, "ibeta", Operation.BETA_INCOMPLETE_REGULARIZED, null); put(1, "gamma", Operation.GAMMA); put(1, "Gamma", Operation.GAMMA, null); put(2, "gamma", Operation.GAMMA_INCOMPLETE, "( <x>, <y> )"); put(2, "Gamma", Operation.GAMMA_INCOMPLETE, null); put(2, "gammaRegularized", Operation.GAMMA_INCOMPLETE_REGULARIZED); put(1, "cosIntegral", Operation.CI); put(1, "CosIntegral", Operation.CI, null); put(1, "sinIntegral", Operation.SI); put(1, "SinIntegral", Operation.SI, null); put(1, "expIntegral", Operation.EI); put(1, "ExpIntegral", Operation.EI, null); // functions that come from Reduce put(2, "gGbInTeGrAl", Operation.INTEGRAL, null); put(2, "gGbSuBsTiTuTiOn", Operation.SUBSTITUTION, null); put(4, "gGbSuM", Operation.SUM, null); put(2, "gGbIfElSe", Operation.IF, null); put(3, "gGbIfElSe", Operation.IF_ELSE, null); put(1, "arbint", Operation.ARBINT); put(1, "arbconst", Operation.ARBCONST); put(1, "arbcomplex", Operation.ARBCOMPLEX); put(1, "sqrt", Operation.SQRT); put(1, "Sqrt", Operation.SQRT, null); put(1, "cbrt", Operation.CBRT); put(1, "Cbrt", Operation.CBRT, null); put(1, "abs", Operation.ABS); put(1, "Abs", Operation.ABS, null); put(1, "sgn", Operation.SGN); put(1, "sign", Operation.SGN); put(1, "Sign", Operation.SGN, null); put(1, "floor", Operation.FLOOR); put(1, "Floor", Operation.FLOOR, null); put(1, "ceil", Operation.CEIL); put(1, "Ceil", Operation.CEIL, null); put(1, "round", Operation.ROUND); put(1, "Round", Operation.ROUND, null); put(2, "round", Operation.ROUND2, "( <x>, <y> )"); put(2, "Round", Operation.ROUND2, null); put(1, "conjugate", Operation.CONJUGATE); put(1, "Conjugate", Operation.CONJUGATE, null); put(1, "arg", Operation.ARG); put(1, "Arg", Operation.ARG, null); put(1, "alt", Operation.ALT); put(1, "Alt", Operation.ALT, null); put(0, "random", Operation.RANDOM, "()"); put(1, "x", Operation.XCOORD, null); put(1, "y", Operation.YCOORD, null); put(1, "z", Operation.ZCOORD, null); put(2, "nroot", Operation.NROOT, "( <x>, <n> )"); put(2, "NRoot", Operation.NROOT, null); put(1, "Real", Operation.REAL, null); put(1, "real", Operation.REAL); put(1, "Imaginary", Operation.IMAGINARY, null); put(1, "imaginary", Operation.IMAGINARY); put(1, "fractionalpart", Operation.FRACTIONAL_PART, null); put(1, "fractionalPart", Operation.FRACTIONAL_PART); put(1, "FractionalPart", Operation.FRACTIONAL_PART, null); put(2, "ggbdiff", Operation.DIFF, null); put(3, "ggbdiff", Operation.DIFF, null); put(1, "vectorize", Operation.MATRIXTOVECTOR, null); RESERVED_FUNCTION_NAMES.add(Unicode.IMAGINARY); RESERVED_FUNCTION_NAMES.add("freehand"); RESERVED_FUNCTION_NAMES.add("deg"); } private static String[] translateable1var = new String[] { "sin", "cos", "tan", "cot", "csc", "sec", "sinh", "cosh", "tanh", "coth", "csch", "sech", "asin", "acos", "atan", "asind", "acosd", "atand", "asinh", "acosh", "atanh", "real", "imaginary", "conjugate", "fractionalPart" }; /** * Updates local names of functions * * @param loc * localization */ public void updateLocale(Localization loc) { // reset is expensive, do not do that if we only have intl. function // names so far if (this.localeLoaded) { reset(); } this.localeLoaded = true; for (String fn : translateable1var) { put(1, loc.getFunction(fn), get(fn, 1)); } put(2, loc.getFunction("nroot"), Operation.NROOT, "( <x>, <n> )"); } /** * @param s * function name * @param size * number of arguments * @return operation */ public Operation get(String s, int size) { if (size > MAX_ARGS) { return null; } Operation ret = stringToOp.get(size).get(s); if (!this.inverseTrig || ret == null) { return ret; } switch (ret) { case ARCSIN: return Operation.ARCSIND; case ARCTAN: return Operation.ARCTAND; case ARCCOS: return Operation.ARCCOSD; case ARCTAN2: return Operation.ARCTAN2D; default: return ret; } } private void put(int size, String name, Operation op) { put(size, name, op, "( <x> )"); } private void put(int size, String name, Operation op, String arg) { RESERVED_FUNCTION_NAMES.add(name); if (arg != null) { syntaxes.add(name + arg); } if (size > MAX_ARGS) { return; } stringToOp.get(size).put(name, op); } /** * Some names cannot be used for elements because of collision with * predefined functions these should also be documented here: * http://wiki.geogebra.org/en/Manual:Naming_Objects * * @param s * label * @return true if label is reserved */ public boolean isReserved(String s) { return RESERVED_FUNCTION_NAMES.contains(s); } /** * Find completions for a given prefix (Arnaud 03/10/2011) * * @param prefix * the wanted prefix * @return all the built-in functions starting with this prefix (with * brackets at the end) */ public ArrayList<String> getCompletions(String prefix) { ArrayList<String> completions = new ArrayList<String>(); Iterator<String> candidates = syntaxes.tailSet(prefix).iterator(); while (candidates.hasNext()) { String candidate = candidates.next(); if (!candidate.startsWith(prefix)) { break; } completions.add(candidate); } return completions; } /** * @param loc * localization * @param string * translated function * @return English function name */ public String getInternal(Localization loc, String string) { for (int i = 0; i < translateable1var.length; i++) { if (loc.getFunction(translateable1var[i]).equals(string)) { return translateable1var[i]; } } if (loc.getFunction("nroot").equals(string)) { return "nroot"; } return null; } /** * @param string * english function name * @return whether this is a translateable function */ public boolean isFunction(String string) { for (int i = 0; i < translateable1var.length; i++) { if (translateable1var[i].equals(string)) { return true; } } return "nroot".equals(string); } /** * @param deg * whether inverse trig functions should be replaced by deg * variants */ public void setInverseTrig(boolean deg) { this.inverseTrig = deg; } }