1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jexl3.internal;
18
19 import java.util.Arrays;
20 import java.util.Objects;
21
22 import org.apache.commons.jexl3.JexlContext;
23 import org.apache.commons.jexl3.JexlOptions;
24 import org.apache.commons.jexl3.parser.ASTJexlLambda;
25
26
27
28
29 public class Closure extends Script {
30
31
32 protected final Frame frame;
33
34
35 protected final JexlOptions options;
36
37
38
39
40
41
42
43 protected Closure(final Interpreter theCaller, final ASTJexlLambda lambda) {
44 super(theCaller.jexl, null, lambda);
45 frame = lambda.createFrame(theCaller.frame);
46 final JexlOptions callerOptions = theCaller.options;
47 options = callerOptions != null ? callerOptions.copy() : null;
48 }
49
50
51
52
53
54
55
56 protected Closure(final Script base, final Object[] args) {
57 super(base.jexl, base.source, base.script);
58 final Frame sf = base instanceof Closure ? ((Closure) base).frame : null;
59 frame = sf == null
60 ? script.createFrame(args)
61 : sf.assign(args);
62 JexlOptions closureOptions = null;
63 if (base instanceof Closure) {
64 closureOptions = ((Closure) base).options;
65 }
66 options = closureOptions != null ? closureOptions.copy() : null;
67 }
68
69 @Override
70 public Callable callable(final JexlContext context, final Object... args) {
71 final Frame local = frame != null ? frame.assign(args) : null;
72 return new Callable(createInterpreter(context, local, options)) {
73 @Override
74 public Object interpret() {
75 return interpreter.runClosure(Closure.this);
76 }
77 };
78 }
79
80
81
82
83
84
85
86
87
88
89
90
91 void captureSelfIfRecursive(final Frame parentFrame, final int symbol) {
92 if (script instanceof ASTJexlLambda) {
93 final Scope parentScope = parentFrame != null ? parentFrame.getScope() : null;
94 final Scope localScope = frame != null ? frame.getScope() : null;
95 if (parentScope != null && localScope != null && parentScope == localScope.getParent()) {
96 final Integer reg = localScope.getCaptured(symbol);
97 if (reg != null) {
98 frame.set(reg, this);
99 }
100 }
101 }
102 }
103
104 @Override
105 public boolean equals(final Object obj) {
106 if (obj == null) {
107 return false;
108 }
109 if (getClass() != obj.getClass()) {
110 return false;
111 }
112 final Closure other = (Closure) obj;
113 if (this.jexl != other.jexl) {
114 return false;
115 }
116 if (!Objects.equals(this.source, other.source)) {
117 return false;
118 }
119 if (this.frame == other.frame) {
120 return true;
121 }
122 return Arrays.deepEquals(
123 this.frame.nocycleStack(this),
124 other.frame.nocycleStack(other));
125 }
126
127 @Override
128 public Object evaluate(final JexlContext context) {
129 return execute(context, (Object[])null);
130 }
131
132 @Override
133 public Object execute(final JexlContext context) {
134 return execute(context, (Object[])null);
135 }
136
137 @Override
138 public Object execute(final JexlContext context, final Object... args) {
139 final Frame local = frame != null ? frame.assign(args) : null;
140 final Interpreter interpreter = createInterpreter(context, local, options);
141 return interpreter.runClosure(this);
142 }
143
144 @Override
145 public String[] getUnboundParameters() {
146 return frame.getUnboundParameters();
147 }
148
149 @Override
150 public int hashCode() {
151
152 int hash = 17;
153 hash = 31 * hash + Objects.hashCode(jexl);
154 hash = 31 * hash + Objects.hashCode(source);
155 hash = 31 * hash + (frame != null ? Arrays.deepHashCode(frame.nocycleStack(this)) : 0);
156
157 return hash;
158 }
159
160 }