1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.jexl2.parser;
18
19 import org.apache.commons.jexl2.DebugInfo;
20 import org.apache.commons.jexl2.JexlEngine;
21 import org.apache.commons.jexl2.JexlException;
22
23 /**
24 * The base class for parsing, manages the parameter/local variable frame.
25 * @author henri
26 */
27 public class JexlParser extends StringParser {
28 /**
29 * The map of named registers aka script parameters.
30 * Each parameter is associated to a register and is materialized as an offset in the registers array used
31 * during evaluation.
32 */
33 protected JexlEngine.Scope frame;
34
35 /**
36 * Sets the frame to use bythis parser.
37 * <p>
38 * This is used to allow parameters to be declared before parsing.
39 * </p>
40 * @param theFrame the register map
41 */
42 public void setFrame(JexlEngine.Scope theFrame) {
43 frame = theFrame;
44 }
45
46 /**
47 * Gets the frame used by this parser.
48 * <p>
49 * Since local variables create new named registers, it is important to regain access after
50 * parsing to known which / how-many registers are needed.
51 * </p>
52 * @return the named register map
53 */
54 public JexlEngine.Scope getFrame() {
55 return frame;
56 }
57
58
59 /**
60 * Checks whether an identifier is a local variable or argument, ie stored in a register.
61 * @param identifier the identifier
62 * @param image the identifier image
63 * @return the image
64 */
65 public String checkVariable(ASTIdentifier identifier, String image) {
66 if (frame != null) {
67 Integer register = frame.getRegister(image);
68 if (register != null) {
69 identifier.setRegister(register.intValue());
70 }
71 }
72 return image;
73 }
74
75 /**
76 * Declares a local variable.
77 * <p>
78 * This method creates an new entry in the named register map.
79 * </p>
80 * @param identifier the identifier used to declare
81 * @param image the variable name
82 */
83 public void declareVariable(ASTVar identifier, String image) {
84 if (frame == null) {
85 frame = new JexlEngine.Scope((String[])null);
86 }
87 Integer register = frame.declareVariable(image);
88 identifier.setRegister(register.intValue());
89 identifier.image = image;
90 }
91
92 /**
93 * Default implementation does nothing but is overriden by generated code.
94 * @param top whether the identifier is beginning an l/r value
95 * @throws ParseException subclasses may throw this
96 */
97 public void Identifier(boolean top) throws ParseException {
98 // Overriden by generated code
99 }
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 }