    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.parser;
    018
    019    import org.apache.commons.jexl2.DebugInfo;
    020    import org.apache.commons.jexl2.JexlEngine;
    021    import org.apache.commons.jexl2.JexlException;
    022
    023    /**
    024     * The base class for parsing, manages the parameter/local variable frame.
    025     * @author henri
    026     */
    027    public class JexlParser extends StringParser {
    028        /**
    029         * The map of named registers aka script parameters.
    030         * Each parameter is associated to a register and is materialized as an offset in the registers array used
    031         * during evaluation.
    032         */
    033        protected JexlEngine.Scope frame;
    034
    035        /**
    036         * Sets the frame to use bythis parser.
    037         * <p>
    038         * This is used to allow parameters to be declared before parsing.
    039         * </p>
    040         * @param theFrame the register map
    041         */
    042        public void setFrame(JexlEngine.Scope theFrame) {
    043            frame = theFrame;
    044        }
    045
    046        /**
    047         * Gets the frame used by this parser.
    048         * <p>
    049         * Since local variables create new named registers, it is important to regain access after
    050         * parsing to known which / how-many registers are needed.
    051         * </p>
    052         * @return the named register map
    053         */
    054        public JexlEngine.Scope getFrame() {
    055            return frame;
    056        }
    057
    058
    059        /**
    060         * Checks whether an identifier is a local variable or argument, ie stored in a register.
    061         * @param identifier the identifier
    062         * @param image the identifier image
    063         * @return the image
    064         */
    065        public String checkVariable(ASTIdentifier identifier, String image) {
    066            if (frame != null) {
    067                Integer register = frame.getRegister(image);
    068                if (register != null) {
    069                    identifier.setRegister(register.intValue());
    070                }
    071            }
    072            return image;
    073        }
    074
    075        /**
    076         * Declares a local variable.
    077         * <p>
    078         * This method creates an new entry in the named register map.
    079         * </p>
    080         * @param identifier the identifier used to declare
    081         * @param image the variable name
    082         */
    083        public void declareVariable(ASTVar identifier, String image) {
    084            if (frame == null) {
    085                frame = new JexlEngine.Scope((String[])null);
    086            }
    087            Integer register = frame.declareVariable(image);
    088            identifier.setRegister(register.intValue());
    089            identifier.image = image;
    090        }
    091
    092        /**
    093         * Default implementation does nothing but is overriden by generated code.
    094         * @param top whether the identifier is beginning an l/r value
    095         * @throws ParseException subclasses may throw this
    096         */
    097        public void Identifier(boolean top) throws ParseException {
    098            // Overriden by generated code
    099        }
    100
    101        final public void Identifier() throws ParseException {
    102            Identifier(false);
    103        }
    104
    105        public Token getToken(int index) {
    106            return null;
    107        }
    108
    109        void jjtreeOpenNodeScope(JexlNode n) {
    110        }
    111
    112        /**
    113         * Ambiguous statement detector.
    114         * @param n the node
    115         * @throws ParseException
    116         */
    117        void jjtreeCloseNodeScope(JexlNode n) throws ParseException {
    118            if (n instanceof ASTAmbiguous && n.jjtGetNumChildren() > 0) {
    119                DebugInfo dbgInfo = null;
    120                Token tok = this.getToken(0);
    121                if (tok != null) {
    122                    dbgInfo = new DebugInfo(tok.image, tok.beginLine, tok.beginColumn);
    123                } else {
    124                    dbgInfo = n.debugInfo();
    125                }
    126                throw new JexlException.Parsing(dbgInfo, "Ambiguous statement, missing ';' between expressions", null);
    127            }
    128        }
    129    }