@@ -42,8 +42,8 @@ public abstract class BaseExpression implements Expression {
4242 private static final long serialVersionUID = 2819544277750883372L ;
4343
4444 public static final String FUNC_PARAMS_VAR = "__funcs_args__" ;
45- protected List <String > varNames ;
46- protected List <String > varFullNames ;
45+ protected transient List <String > varNames ;
46+ protected transient List <String > varFullNames ;
4747 private List <VariableMeta > vars ;
4848 private String expression ;
4949 protected transient AviatorEvaluatorInstance instance ;
@@ -53,6 +53,12 @@ public abstract class BaseExpression implements Expression {
5353 // cached compiled string segments for string interpolation.
5454 private transient ConcurrentHashMap <String , FutureTask <StringSegments >> stringSegs =
5555 new ConcurrentHashMap <String , FutureTask <StringSegments >>();
56+ // The function name list in expression
57+ private List <String > functionNames = Collections .emptyList ();
58+
59+ // Already filtered function names, try to remove the runtime defined functions.
60+ private transient List <String > filteredFunctionNames = null ;
61+
5662
5763 protected String sourceFile ;
5864 protected Map <String , LambdaFunctionBootstrap > lambdaBootstraps ;
@@ -62,12 +68,12 @@ public String getSourceFile() {
6268 return this .sourceFile ;
6369 }
6470
65- public void setSourceFile (final String sourceFile ) {
71+ protected void setSourceFile (final String sourceFile ) {
6672 this .sourceFile = sourceFile ;
6773 }
6874
6975
70- public void setInstance (AviatorEvaluatorInstance instance ) {
76+ protected void setInstance (AviatorEvaluatorInstance instance ) {
7177 this .instance = instance ;
7278 }
7379
@@ -264,7 +270,7 @@ protected Object execute(Map<String, Object> map, boolean checkExecutionTimeout)
264270 }
265271 }
266272
267- public void setFuncsArgs (final Map <Integer , List <FunctionArgument >> funcsArgs ) {
273+ protected void setFuncsArgs (final Map <Integer , List <FunctionArgument >> funcsArgs ) {
268274 if (funcsArgs != null ) {
269275 this .funcsArgs = Collections .unmodifiableMap (funcsArgs );
270276 }
@@ -274,7 +280,7 @@ public Env getCompileEnv() {
274280 return this .compileEnv ;
275281 }
276282
277- public void setCompileEnv (final Env compileEnv ) {
283+ protected void setCompileEnv (final Env compileEnv ) {
278284 this .compileEnv = compileEnv ;
279285 this .compileEnv .setExpression (this );
280286 }
@@ -289,7 +295,7 @@ public String getExpression() {
289295 return this .expression ;
290296 }
291297
292- public void setExpression (final String expression ) {
298+ protected void setExpression (final String expression ) {
293299 this .expression = expression ;
294300 }
295301
@@ -374,11 +380,57 @@ protected Env newEnv(final Map<String, Object> map) {
374380 return newEnv (map , false , true );
375381 }
376382
383+ public List <String > getFunctionNames () {
384+ populateFilteredFuncNames ();
385+
386+ return filteredFunctionNames ;
387+ }
388+
389+ private void populateFilteredFuncNames () {
390+ if (this .filteredFunctionNames == null ) {
391+ Set <String > validNames = new HashSet <String >(this .functionNames .size ());
392+
393+ for (String funcName : this .functionNames ) {
394+ // Remove internal functions
395+ if (!funcName .startsWith ("__" ) && !funcName .equals ("with_meta" )) {
396+ validNames .add (funcName );
397+ }
398+ }
399+
400+ Set <String > definedFuncs = new HashSet <String >();
401+ // Find all runtime defined functions
402+ for (VariableMeta v : this .vars ) {
403+ // TODO: It's not precise, but could work
404+ if (v .isInit ()) {
405+ definedFuncs .add (v .getName ());
406+ }
407+ }
408+
409+ if (this .lambdaBootstraps != null ) {
410+ // Adds sub-expressions function names
411+ for (LambdaFunctionBootstrap bootstrap : this .lambdaBootstraps .values ()) {
412+ validNames .addAll (bootstrap .getExpression ().getFunctionNames ());
413+ }
414+ }
415+
416+ // Remove runtime defined functions.
417+ validNames .removeAll (definedFuncs );
418+
419+ this .filteredFunctionNames = new ArrayList <>(validNames );
420+ }
421+ }
422+
423+ protected void setFunctionNames (List <String > functionNames ) {
424+ if (functionNames != null ) {
425+ this .functionNames = functionNames ;
426+ }
427+ }
428+
377429 public Map <String , LambdaFunctionBootstrap > getLambdaBootstraps () {
378430 return this .lambdaBootstraps ;
379431 }
380432
381- public void setLambdaBootstraps (final Map <String , LambdaFunctionBootstrap > lambdaBootstraps ) {
433+ protected void setLambdaBootstraps (final Map <String , LambdaFunctionBootstrap > lambdaBootstraps ) {
382434 this .lambdaBootstraps = lambdaBootstraps ;
383435 }
384436
@@ -400,6 +452,7 @@ public void customReadObject(ObjectInputStream input) throws ClassNotFoundExcept
400452 this .sourceFile = (String ) input .readObject ();
401453 this .lambdaBootstraps = (Map <String , LambdaFunctionBootstrap >) input .readObject ();
402454 this .stringSegs = new ConcurrentHashMap <String , FutureTask <StringSegments >>();
455+ this .functionNames = (List <String >) input .readObject ();
403456 }
404457
405458 public void customWriteObject (ObjectOutputStream output ) throws IOException {
@@ -410,6 +463,7 @@ public void customWriteObject(ObjectOutputStream output) throws IOException {
410463 output .writeObject (this .symbolTable );
411464 output .writeObject (this .sourceFile );
412465 output .writeObject (this .lambdaBootstraps );
466+ output .writeObject (this .functionNames );
413467 }
414468
415469}
0 commit comments