View Javadoc
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.jexl3.internal;
18  
19  
20  import org.apache.commons.jexl3.JexlBuilder;
21  import org.apache.commons.jexl3.JexlContext;
22  import org.apache.commons.jexl3.JexlOptions;
23  import org.apache.commons.jexl3.parser.ASTArrayAccess;
24  import org.apache.commons.jexl3.parser.ASTAssignment;
25  import org.apache.commons.jexl3.parser.ASTEQNode;
26  import org.apache.commons.jexl3.parser.ASTIdentifier;
27  import org.apache.commons.jexl3.parser.ASTNENode;
28  import org.apache.commons.jexl3.parser.ASTNullpNode;
29  import org.apache.commons.jexl3.parser.ASTReference;
30  import org.apache.commons.jexl3.parser.ASTTernaryNode;
31  import org.apache.commons.jexl3.parser.JexlNode;
32  
33  /**
34   * An Engine that behaves like JEXL 3.2, bugs included.
35   */
36  public class Engine32 extends Engine {
37      public Engine32(final JexlBuilder conf) {
38          super(conf);
39      }
40  
41      public Engine32() {
42      }
43  
44      /**
45       * Static delegation of isTernaryProtected.
46       * @param ii the interpreter (unused)
47       * @param node the node
48       * @return true if node is navigation-safe, false otherwise
49       */
50      static boolean isTernaryProtected(final Interpreter ii, JexlNode node) {
51          for (JexlNode walk = node.jjtGetParent(); walk != null; walk = walk.jjtGetParent()) {
52              // protect only the condition part of the ternary
53              if (walk instanceof ASTTernaryNode
54                      || walk instanceof ASTNullpNode
55                      || walk instanceof ASTEQNode
56                      || walk instanceof ASTNENode) {
57                  return node == walk.jjtGetChild(0);
58              }
59              if (!(walk instanceof ASTReference || walk instanceof ASTArrayAccess)) {
60                  break;
61              }
62              node = walk;
63          }
64          return false;
65      }
66  
67      /**
68       * Static delegation of getVariable.
69       * @param ii the interpreter
70       * @param frame the frame
71       * @param block the scope
72       * @param identifier the variable identifier
73       * @return the variable value
74       */
75      static Object getVariable(final Interpreter ii, final Frame frame, final LexicalScope block, final ASTIdentifier identifier) {
76          final int symbol = identifier.getSymbol();
77          // if we have a symbol, we have a scope thus a frame
78          if ((ii.options.isLexicalShade() || identifier.isLexical()) && identifier.isShaded()) {
79              return ii.undefinedVariable(identifier, identifier.getName());
80          }
81          if (symbol >= 0) {
82              if (frame.has(symbol)) {
83                  final Object value = frame.get(symbol);
84                  if (value != Scope.UNDEFINED) {
85                      return value;
86                  }
87              }
88          }
89          final String name = identifier.getName();
90          final Object value = ii.context.get(name);
91          if (value == null && !ii.context.has(name)) {
92              final boolean ignore = (ii.isSafe()
93                      && (symbol >= 0
94                      || identifier.jjtGetParent() instanceof ASTAssignment))
95                      || (identifier.jjtGetParent() instanceof ASTReference);
96              if (!ignore) {
97                  return ii.unsolvableVariable(identifier, name, true); // undefined
98              }
99          }
100         return value;
101     }
102 
103     @Override
104     protected Interpreter createInterpreter(final JexlContext context, final Frame frame, final JexlOptions opts) {
105         return new Interpreter(this, opts, context, frame) {
106             @Override
107             protected boolean isStrictOperand(final JexlNode node) {
108                 return false;
109             }
110 
111             @Override
112             protected boolean isTernaryProtected( final JexlNode node) {
113                 return Engine32.isTernaryProtected(this, node);
114             }
115 
116             @Override
117             protected Object getVariable(final Frame frame, final LexicalScope block, final ASTIdentifier identifier) {
118                 return Engine32.getVariable(this, frame, block, identifier);
119             }
120         };
121     }
122 
123     @Override
124     protected Interpreter createTemplateInterpreter(final TemplateInterpreter.Arguments args) {
125         return new TemplateInterpreter(args) {
126             @Override
127             protected boolean isStrictOperand(final JexlNode node) {
128                 return false;
129             }
130 
131             @Override
132             protected boolean isTernaryProtected( final JexlNode node) {
133                 return Engine32.isTernaryProtected(this, node);
134             }
135 
136             @Override
137             protected Object getVariable(final Frame frame, final LexicalScope block, final ASTIdentifier identifier) {
138                 return Engine32.getVariable(this, frame, block, identifier);
139             }
140         };
141     }
142 }