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 */
017package org.apache.commons.jexl2;
018
019import java.util.List;
020import java.util.Set;
021import java.util.concurrent.Callable;
022
023import 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 */
031public 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}