001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.jexl2;
018    
019    import java.util.List;
020    import java.util.Set;
021    import java.util.concurrent.Callable;
022    
023    import org.apache.commons.jexl2.parser.ASTJexlScript;
024    
025    /**
026     * Instances of ExpressionImpl are created by the {@link JexlEngine},
027     * and this is the default implementation of the {@link Expression} and
028     * {@link Script} interface.
029     * @since 1.0
030     */
031    public class ExpressionImpl implements Expression, Script {
032        /** The engine for this expression. */
033        protected final JexlEngine jexl;
034        /**
035         * Original expression stripped from leading & trailing spaces.
036         */
037        protected final String expression;
038        /**
039         * The resulting AST we can interpret.
040         */
041        protected final ASTJexlScript script;
042    
043        /**
044         * Do not let this be generally instantiated with a 'new'.
045         *
046         * @param engine the interpreter to evaluate the expression
047         * @param expr the expression.
048         * @param ref the parsed expression.
049         */
050        protected ExpressionImpl(JexlEngine engine, String expr, ASTJexlScript ref) {
051            jexl = engine;
052            expression = expr;
053            script = ref;
054        }
055    
056        /**
057         * {@inheritDoc}
058         */
059        public Object evaluate(JexlContext context) {
060            if (script.jjtGetNumChildren() < 1) {
061                return null;
062            }
063            Interpreter interpreter = jexl.createInterpreter(context);
064            interpreter.setFrame(script.createFrame((Object[]) null));
065            return interpreter.interpret(script.jjtGetChild(0));
066        }
067    
068        /**
069         * {@inheritDoc}
070         */
071        public String dump() {
072            Debugger debug = new Debugger();
073            boolean d = debug.debug(script);
074            return debug.data() + (d ? " /*" + debug.start() + ":" + debug.end() + "*/" : "/*?:?*/ ");
075        }
076    
077        /**
078         * {@inheritDoc}
079         */
080        public String getExpression() {
081            return expression;
082        }
083    
084        /**
085         * Provide a string representation of this expression.
086         * @return the expression or blank if it's null.
087         */
088        @Override
089        public String toString() {
090            String expr = getExpression();
091            return expr == null ? "" : expr;
092        }
093    
094        /**
095         * {@inheritDoc}
096         */
097        public String getText() {
098            return toString();
099        }
100    
101        /**
102         * {@inheritDoc}
103         */
104        public Object execute(JexlContext context) {
105            Interpreter interpreter = jexl.createInterpreter(context);
106            interpreter.setFrame(script.createFrame((Object[]) null));
107            return interpreter.interpret(script);
108        }
109    
110        /**
111         * {@inheritDoc}
112         * @since 2.1
113         */
114        public Object execute(JexlContext context, Object... args) {
115            Interpreter interpreter = jexl.createInterpreter(context);
116            interpreter.setFrame(script.createFrame(args));
117            return interpreter.interpret(script);
118        }
119    
120        /**
121         * {@inheritDoc}
122         * @since 2.1
123         */
124        public String[] getParameters() {
125            return script.getParameters();
126        }
127    
128        /**
129         * {@inheritDoc}
130         * @since 2.1
131         */
132        public String[] getLocalVariables() {
133            return script.getLocalVariables();
134        }
135    
136        /**
137         * {@inheritDoc}
138         * @since 2.1
139         */
140        public Set<List<String>> getVariables() {
141            return jexl.getVariables(this);
142        }
143    
144        /**
145         * {@inheritDoc}
146         * @since 2.1
147         */
148        public Callable<Object> callable(JexlContext context) {
149            return callable(context, (Object[]) null);
150        }
151    
152        /**
153         * {@inheritDoc}
154         * @since 2.1
155         */
156        public Callable<Object> callable(JexlContext context, Object... args) {
157            final Interpreter interpreter = jexl.createInterpreter(context);
158            interpreter.setFrame(script.createFrame(args));
159    
160            return new Callable<Object>() {
161                /** Use interpreter as marker for not having run. */
162                private Object result = interpreter;
163    
164                public Object call() throws Exception {
165                    if (result == interpreter) {
166                        result = interpreter.interpret(script);
167                    }
168                    return result;
169                }
170    
171            };
172        }
173    
174    }