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