Skip to content

Commit

Permalink
Merge pull request #631 from killme2008/feat/get-function-names
Browse files Browse the repository at this point in the history
feat: adds Expression#getFunctionNames
  • Loading branch information
killme2008 authored Jun 9, 2024
2 parents 63990cf + 0ec087c commit 2968544
Show file tree
Hide file tree
Showing 14 changed files with 249 additions and 40 deletions.
2 changes: 1 addition & 1 deletion src/main/java/com/googlecode/aviator/AviatorEvaluator.java
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ public static AviatorFunction removeOpFunction(final OperatorType opType) {


/**
* Check if the function is existed in aviator
* Check if the function exists in the global evaluator instance.
*
* @param name
* @return
Expand Down
15 changes: 13 additions & 2 deletions src/main/java/com/googlecode/aviator/AviatorEvaluatorInstance.java
Original file line number Diff line number Diff line change
Expand Up @@ -1327,13 +1327,24 @@ public AviatorFunction removeOpFunction(final OperatorType opType) {
}

/**
* Check if the function is existed in aviator
* Check if the function exists in the evaluator. Note: it doesn't check the runtime defined
* functions.
*
* @param name
* @return
*/
public boolean containsFunction(final String name) {
return this.funcMap.containsKey(name);
boolean exists = this.funcMap.containsKey(name);
if (!exists && this.functionLoaders != null) {
for (FunctionLoader loader : this.functionLoaders) {
if (loader != null && loader.onFunctionNotFound(name) != null) {
exists = true;
break;
}
}
}

return exists;
}

/**
Expand Down
70 changes: 62 additions & 8 deletions src/main/java/com/googlecode/aviator/BaseExpression.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ public abstract class BaseExpression implements Expression {
private static final long serialVersionUID = 2819544277750883372L;

public static final String FUNC_PARAMS_VAR = "__funcs_args__";
protected List<String> varNames;
protected List<String> varFullNames;
protected transient List<String> varNames;
protected transient List<String> varFullNames;
private List<VariableMeta> vars;
private String expression;
protected transient AviatorEvaluatorInstance instance;
Expand All @@ -53,6 +53,12 @@ public abstract class BaseExpression implements Expression {
// cached compiled string segments for string interpolation.
private transient ConcurrentHashMap<String, FutureTask<StringSegments>> stringSegs =
new ConcurrentHashMap<String, FutureTask<StringSegments>>();
// The function name list in expression
private List<String> functionNames = Collections.emptyList();

// Already filtered function names, try to remove the runtime defined functions.
private transient List<String> filteredFunctionNames = null;


protected String sourceFile;
protected Map<String, LambdaFunctionBootstrap> lambdaBootstraps;
Expand All @@ -62,12 +68,12 @@ public String getSourceFile() {
return this.sourceFile;
}

public void setSourceFile(final String sourceFile) {
protected void setSourceFile(final String sourceFile) {
this.sourceFile = sourceFile;
}


public void setInstance(AviatorEvaluatorInstance instance) {
protected void setInstance(AviatorEvaluatorInstance instance) {
this.instance = instance;
}

Expand Down Expand Up @@ -264,7 +270,7 @@ protected Object execute(Map<String, Object> map, boolean checkExecutionTimeout)
}
}

public void setFuncsArgs(final Map<Integer, List<FunctionArgument>> funcsArgs) {
protected void setFuncsArgs(final Map<Integer, List<FunctionArgument>> funcsArgs) {
if (funcsArgs != null) {
this.funcsArgs = Collections.unmodifiableMap(funcsArgs);
}
Expand All @@ -274,7 +280,7 @@ public Env getCompileEnv() {
return this.compileEnv;
}

public void setCompileEnv(final Env compileEnv) {
protected void setCompileEnv(final Env compileEnv) {
this.compileEnv = compileEnv;
this.compileEnv.setExpression(this);
}
Expand All @@ -289,7 +295,7 @@ public String getExpression() {
return this.expression;
}

public void setExpression(final String expression) {
protected void setExpression(final String expression) {
this.expression = expression;
}

Expand Down Expand Up @@ -374,11 +380,57 @@ protected Env newEnv(final Map<String, Object> map) {
return newEnv(map, false, true);
}

public List<String> getFunctionNames() {
populateFilteredFuncNames();

return filteredFunctionNames;
}

private void populateFilteredFuncNames() {
if (this.filteredFunctionNames == null) {
Set<String> validNames = new HashSet<String>(this.functionNames.size());

for (String funcName : this.functionNames) {
// Remove internal functions
if (!funcName.startsWith("__") && !funcName.equals("with_meta")) {
validNames.add(funcName);
}
}

Set<String> definedFuncs = new HashSet<String>();
// Find all runtime defined functions
for (VariableMeta v : this.vars) {
// TODO: It's not precise, but could work
if (v.isInit()) {
definedFuncs.add(v.getName());
}
}

if (this.lambdaBootstraps != null) {
// Adds sub-expressions function names
for (LambdaFunctionBootstrap bootstrap : this.lambdaBootstraps.values()) {
validNames.addAll(bootstrap.getExpression().getFunctionNames());
}
}

// Remove runtime defined functions.
validNames.removeAll(definedFuncs);

this.filteredFunctionNames = new ArrayList<>(validNames);
}
}

protected void setFunctionNames(List<String> functionNames) {
if (functionNames != null) {
this.functionNames = functionNames;
}
}

public Map<String, LambdaFunctionBootstrap> getLambdaBootstraps() {
return this.lambdaBootstraps;
}

public void setLambdaBootstraps(final Map<String, LambdaFunctionBootstrap> lambdaBootstraps) {
protected void setLambdaBootstraps(final Map<String, LambdaFunctionBootstrap> lambdaBootstraps) {
this.lambdaBootstraps = lambdaBootstraps;
}

Expand All @@ -400,6 +452,7 @@ public void customReadObject(ObjectInputStream input) throws ClassNotFoundExcept
this.sourceFile = (String) input.readObject();
this.lambdaBootstraps = (Map<String, LambdaFunctionBootstrap>) input.readObject();
this.stringSegs = new ConcurrentHashMap<String, FutureTask<StringSegments>>();
this.functionNames = (List<String>) input.readObject();
}

public void customWriteObject(ObjectOutputStream output) throws IOException {
Expand All @@ -410,6 +463,7 @@ public void customWriteObject(ObjectOutputStream output) throws IOException {
output.writeObject(this.symbolTable);
output.writeObject(this.sourceFile);
output.writeObject(this.lambdaBootstraps);
output.writeObject(this.functionNames);
}

}
20 changes: 14 additions & 6 deletions src/main/java/com/googlecode/aviator/Expression.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@
public interface Expression extends Serializable {

/**
* Execute expression with environment
* Execute an expression with an environment, returns the result.
*
* @param env Binding variable environment
* @return
* @return the result of execution
*/
Object execute(Map<String, Object> env);


/**
* Execute expression with empty environment
* Execute an expression with an empty environment, returns the result.
*
* @return
* @return the result of execution
*/
Object execute();

Expand All @@ -55,7 +55,7 @@ public interface Expression extends Serializable {

/**
* Returns this expression's all uninitialized global variable names in order when using
* AviatorEvaluator.EVAL mode,else returns empty set
* AviatorEvaluator.EVAL mode, otherwise returns an empty list.
*
* @see com.googlecode.aviator.AviatorEvaluator#EVAL
* @return
Expand All @@ -65,7 +65,7 @@ public interface Expression extends Serializable {

/**
* Returns this expression's all uninitialized global variable full names(contains dot) in order
* when using AviatorEvaluator.EVAL mode,else returns empty set
* when using AviatorEvaluator.EVAL mode, otherwise returns an empty list.
*
* @return
*/
Expand All @@ -89,4 +89,12 @@ public interface Expression extends Serializable {
*/
String addSymbol(String name);

/**
* Returns the function names in the expression when using AviatorEvaluator.EVAL mode, otherwise
* returns an empty list.
*
* @since 5.4.2
* @return the function name list
*/
List<String> getFunctionNames();
}
61 changes: 61 additions & 0 deletions src/main/java/com/googlecode/aviator/ExpressionAccessor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Copyright (C) 2010 dennis zhuang ([email protected])
*
* This library is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version
* 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
**/
package com.googlecode.aviator;

import java.util.List;
import java.util.Map;
import com.googlecode.aviator.runtime.FunctionArgument;
import com.googlecode.aviator.runtime.LambdaFunctionBootstrap;
import com.googlecode.aviator.utils.Env;

/**
* Base expression default methods accessor
*
* @author dennis
*
*/
public class ExpressionAccessor {

public static void setSourceFile(final BaseExpression exp, String sourceFile) {
exp.setSourceFile(sourceFile);
}

public static void setInstance(final BaseExpression exp, AviatorEvaluatorInstance instance) {
exp.setInstance(instance);
}

public static void setCompileEnv(final BaseExpression exp, final Env compileEnv) {
exp.setCompileEnv(compileEnv);
}

public static void setExpression(final BaseExpression exp, final String expression) {
exp.setExpression(expression);
}

public static void setFuncsArgs(final BaseExpression exp,
final Map<Integer, List<FunctionArgument>> funcsArgs) {
exp.setFuncsArgs(funcsArgs);
}

public static void setLambdaBootstraps(final BaseExpression exp,
final Map<String, LambdaFunctionBootstrap> lambdaBootstraps) {
exp.setLambdaBootstraps(lambdaBootstraps);
}

public static void setFunctionNames(final BaseExpression exp, List<String> functionNames) {
exp.setFunctionNames(functionNames);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public abstract class BaseEvalCodeGenerator implements EvalCodeGenerator {
*/
protected final Env compileEnv;

protected Map<String, Integer/* counter */> methodTokens = Collections.emptyMap();

protected Map<Integer/* internal function id */, List<FunctionArgument>> getFuncsArgs() {
if (this.funcsArgs == null) {
this.funcsArgs = new HashMap<>();
Expand All @@ -54,6 +56,11 @@ protected int getNextFuncInvocationId() {
return this.funcInvocationId++;
}

@Override
public void initMethods(Map<String, Integer> methods) {
this.methodTokens = methods;
}

@Override
public void setParser(final Parser parser) {
this.parser = parser;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.googlecode.aviator.AviatorEvaluatorInstance;
import com.googlecode.aviator.BaseExpression;
import com.googlecode.aviator.Expression;
import com.googlecode.aviator.ExpressionAccessor;
import com.googlecode.aviator.Feature;
import com.googlecode.aviator.LiteralExpression;
import com.googlecode.aviator.exception.CompileExpressionErrorException;
Expand Down Expand Up @@ -448,8 +449,8 @@ public Expression getResult(final boolean unboxObject) {


if (exp instanceof BaseExpression) {
((BaseExpression) exp).setCompileEnv(getCompileEnv());
((BaseExpression) exp).setSourceFile(this.sourceFile);
ExpressionAccessor.setCompileEnv((BaseExpression) exp, getCompileEnv());
ExpressionAccessor.setSourceFile((BaseExpression) exp, this.sourceFile);
}
return exp;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import com.googlecode.aviator.AviatorEvaluatorInstance;
import com.googlecode.aviator.ClassExpression;
import com.googlecode.aviator.Expression;
import com.googlecode.aviator.ExpressionAccessor;
import com.googlecode.aviator.Options;
import com.googlecode.aviator.asm.ClassWriter;
import com.googlecode.aviator.asm.Label;
Expand Down Expand Up @@ -127,8 +128,6 @@ public class ASMCodeGenerator extends BaseEvalCodeGenerator {
private Map<Token<?>/* constant token */, String/* field name */> constantPool =
Collections.emptyMap();

private Map<String, Integer/* counter */> methodTokens = Collections.emptyMap();

private final Map<Label, Map<String/* inner name */, Integer/* local index */>> labelNameIndexMap =
new IdentityHashMap<>();
private static final Label START_LABEL = new Label();
Expand Down Expand Up @@ -730,9 +729,10 @@ public Expression getResult(final boolean unboxObject) {
defineClass.getConstructor(AviatorEvaluatorInstance.class, List.class, SymbolTable.class);
ClassExpression exp = (ClassExpression) constructor.newInstance(this.instance,
new ArrayList<VariableMeta>(this.variables.values()), this.symbolTable);
exp.setLambdaBootstraps(this.lambdaBootstraps);
exp.setFuncsArgs(this.funcsArgs);
exp.setSourceFile(this.sourceFile);
ExpressionAccessor.setLambdaBootstraps(exp, this.lambdaBootstraps);
ExpressionAccessor.setFuncsArgs(exp, this.funcsArgs);
ExpressionAccessor.setSourceFile(exp, this.sourceFile);
ExpressionAccessor.setFunctionNames(exp, new ArrayList<>(this.methodTokens.keySet()));
if (enableSerializable) {
exp.setClassBytes(bytes);
}
Expand Down Expand Up @@ -1048,7 +1048,7 @@ public void initConstants(final Set<Token<?>> constants) {

@Override
public void initMethods(final Map<String, Integer/* counter */> methods) {
this.methodTokens = methods;
super.initMethods(methods);
this.innerMethodMap = new HashMap<>(methods.size());
for (String outterMethodName : methods.keySet()) {
// Use inner method name instead of outter method name
Expand Down
Loading

0 comments on commit 2968544

Please sign in to comment.