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    }