Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds Expression#getFunctionNames #631

Merged
merged 2 commits into from
Jun 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading