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  import java.util.Arrays;
20  
21  /**
22   * A call frame, created from a scope, stores the arguments and local variables in a "stack frame" (sic).
23   * @since 3.0
24   */
25  public final class Frame {
26      /** The scope. */
27      private final Scope scope;
28      /** The actual stack frame. */
29      private final Object[] stack;
30      /** Number of curried parameters. */
31      private final int curried;
32  
33      /**
34       * Creates a new frame.
35       * @param s the scope
36       * @param r the stack frame
37       * @param c the number of curried parameters
38       */
39      Frame(final Scope s, final Object[] r, final int c) {
40          scope = s;
41          stack = r;
42          curried = c;
43      }
44  
45      /**
46       * Replace any instance of a closure in this stack by its (fuzzy encoded) offset in it.
47       * <p>This is to avoid the cyclic dependency between the closure and its frame stack that
48       * may point back to it that occur with recursive function definitions.</p>
49       * @param closure the owning closure
50       * @return the cleaned-up stack or the stack itself (most of the time)
51       */
52      Object[] nocycleStack(Closure closure) {
53          Object[] ns = stack;
54          for(int i = 0; i < stack.length; ++i) {
55              if (stack[i] == closure) {
56                  if (ns == stack) {
57                      ns = stack.clone();
58                  }
59                  // fuzz it a little
60                  ns[i] = Closure.class.hashCode() + i;
61              }
62          }
63          return ns;
64      }
65  
66      /**
67       * Gets this script unbound parameters, i.e. parameters not bound through curry().
68       * @return the parameter names
69       */
70      public String[] getUnboundParameters() {
71          return scope.getParameters(curried);
72      }
73  
74      /**
75       * Gets the scope.
76       * @return this frame scope
77       */
78      public Scope getScope() {
79          return scope;
80      }
81  
82      /**
83       * Gets a value.
84       * @param s the offset in this frame
85       * @return the stacked value
86       */
87      Object get(final int s) {
88          return stack[s];
89      }
90  
91      /**
92       * Whether this frame defines a symbol, ie declared it and assigned it a value.
93       * @param s the offset in this frame
94       * @return true if this symbol has been assigned a value, false otherwise
95       */
96      boolean has(final int s) {
97          return s >= 0 && s < stack.length && stack[s] != Scope.UNDECLARED;
98      }
99  
100     /**
101      * Sets a value.
102      * @param r the offset in this frame
103      * @param value the value to set in this frame
104      */
105     void set(final int r, final Object value) {
106         stack[r] = value;
107     }
108 
109     /**
110      * Assign values to this frame.
111      * @param values the values
112      * @return this frame
113      */
114     Frame assign(final Object... values) {
115         if (stack != null) {
116             final int nparm = scope.getArgCount();
117             final Object[] copy = stack.clone();
118             int ncopy = 0;
119             if (values != null && values.length > 0) {
120                 ncopy = Math.min(nparm - curried, Math.min(nparm, values.length));
121                 System.arraycopy(values, 0, copy, curried, ncopy);
122             }
123             // unbound parameters are defined as null
124             Arrays.fill(copy, curried + ncopy, nparm, null);
125             return new Frame(scope, copy, curried + ncopy);
126         }
127         return this;
128     }
129 
130 }