package net.sourceforge.mayfly.evaluation.expression; import net.sourceforge.mayfly.MayflyException; import net.sourceforge.mayfly.MayflyInternalException; import net.sourceforge.mayfly.Options; import net.sourceforge.mayfly.UnimplementedException; import net.sourceforge.mayfly.datastore.Cell; import net.sourceforge.mayfly.evaluation.Expression; import net.sourceforge.mayfly.evaluation.ResultRow; import net.sourceforge.mayfly.evaluation.ResultRows; import net.sourceforge.mayfly.evaluation.select.Evaluator; import net.sourceforge.mayfly.parser.Location; import net.sourceforge.mayfly.util.ImmutableList; public class Function extends Expression { public static Expression create( String name, ImmutableList<Expression> arguments, Location location, Options options) { if (name.equalsIgnoreCase("concat")) { return concat(arguments, location, options); } else { return new Function(name, arguments, location, options); } } private static Expression concat(ImmutableList<Expression> arguments, Location location, Options options) { if (arguments.isEmpty()) { throw new MayflyInternalException( "parser should require at least one argument"); } else if (arguments.size() == 1) { return arguments.get(0); } else { /* Not sure associativity matters, but we turn concat(a, b, c) into (a || b) || c not a || (b || c) */ Expression last = arguments.last(); Expression allButLast = concat( arguments.allButLast(), location, options); return new Concatenate(allButLast, last); } } final String className; final String methodName; final Class classObject; public Function(String name, ImmutableList<Expression> arguments, Location location, Options options) { super(location); int lastPeriod = name.lastIndexOf('.'); if (lastPeriod == -1) { /* The more likely reason is not that a period was intended, but that a built-in or aliased function is misspelled. */ throw new MayflyException("no function " + name, location); // throw new MayflyException("function name " + name + // " does not contain a period", location); } this.className = name.substring(0, lastPeriod); this.methodName = name.substring(lastPeriod + 1); try { this.classObject = Class.forName(className); } catch (ClassNotFoundException e) { /* Is there any reason to supply e as the cause? * Normally, I'm loath to potentially destroy information about * what happened. But is there any interesting information to * destroy here? */ throw new MayflyException( "function name specifies Java class " + className + " which is not found", location); } // try { // classObject.getMethod(methodName, new Class[0]); // } // catch (NoSuchMethodException e) { // throw new MayflyException( // "function name specifies method " + methodName + // " which is not found in " + classObject.getName(), // location); // } } @Override public Cell aggregate(ResultRows rows) { throw new UnimplementedException(); } @Override public Cell evaluate(ResultRow row, Evaluator evaluator) { throw new UnimplementedException(); } @Override public boolean sameExpression(Expression other) { throw new UnimplementedException(); } @Override public String displayName() { return "function call"; } }