001/*
002 * Copyright (c) 2012-2018 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others
003 *
004 * This program and the accompanying materials are made available under the
005 * terms of the Eclipse Public License 2.0 which is available at
006 * http://www.eclipse.org/legal/epl-2.0.
007 *
008 * SPDX-License-Identifier: EPL-2.0
009 */
010
011package gololang.ir;
012
013import java.util.Collection;
014import java.util.List;
015
016/**
017 * A closure reference.
018 * <p>
019 * A closure reference is a wrapper around a golo function, to represent a closure or a lambda.
020 * For instance, the golo code:
021 * <pre class="listing"><code class="lang-golo" data-lang="golo">
022 * foo(|x| -> x + 1)
023 * </code></pre>
024 * The argument of the call to {@code foo} is a {@code ClosureReference} wrapping the actual {@link GoloFunction}
025 *
026 * <p>To ease manipulating this node, it delegate most of its methods to the wrapped target function.
027 *
028 * @see GoloFunction#asClosure()
029 * @see GoloFunction#asClosureReference()
030 */
031public class ClosureReference extends ExpressionStatement<ClosureReference> implements BlockContainer<ClosureReference> {
032
033  private GoloFunction target;
034
035  ClosureReference(GoloFunction target) {
036    super();
037    setTarget(target);
038  }
039
040  protected ClosureReference self() { return this; }
041
042  public GoloFunction getTarget() {
043    return target;
044  }
045
046  private void setTarget(GoloFunction target) {
047    this.target = makeParentOf(target);
048    this.positionInSourceCode(target.positionInSourceCode());
049    this.documentation(target.documentation());
050  }
051
052  /**
053   * Delegates on the wrapped target.
054   * @see GoloFunction#getSyntheticParameterNames()
055   */
056  public Collection<String> getCapturedReferenceNames() {
057    return target.getSyntheticParameterNames();
058  }
059
060  /**
061   * Checks if this reference has closed variables.
062   */
063  public boolean hasCapturedReferences() {
064    return target.getSyntheticParameterCount() > 0;
065  }
066
067  /**
068   * Delegates on the wrapped target.
069   * @see GoloFunction#body(Object...)
070   */
071  @Override
072  public ClosureReference body(Object... statements) {
073    this.target.body(statements);
074    return this;
075  }
076
077  /**
078   * Delegates on the wrapped target.
079   * @see GoloFunction#block(Object)
080   */
081  @Override
082  public ClosureReference block(Object block) {
083    this.target.block(block);
084    return this;
085  }
086
087  /**
088   * Delegates on the wrapped target.
089   * @see GoloFunction#getBlock()
090   */
091  @Override
092  public Block getBlock() {
093    return this.target.getBlock();
094  }
095
096  /**
097   * Delegates on the wrapped target.
098   * @see GoloFunction#returns(Object)
099   */
100  public ClosureReference returns(Object expression) {
101    this.target.returns(expression);
102    return this;
103  }
104
105  /**
106   * Delegates on the wrapped target.
107   * @see GoloFunction#varargs()
108   */
109  public ClosureReference varargs() {
110    this.target.varargs();
111    return this;
112  }
113
114  public ClosureReference varargs(boolean v) {
115    this.target.varargs(v);
116    return this;
117  }
118
119  /**
120   * Delegates on the wrapped target.
121   * @see GoloFunction#isVarargs()
122   */
123  public boolean isVarargs() {
124    return this.target.isVarargs();
125  }
126
127  /**
128   * Delegates on the wrapped target.
129   * @see GoloFunction#withParameters(Collection)
130   */
131  public ClosureReference withParameters(Collection<String> paramNames) {
132    this.target.withParameters(paramNames);
133    return this;
134  }
135
136  /**
137   * {@inheritDoc}
138   */
139  @Override
140  public void accept(GoloIrVisitor visitor) {
141    visitor.visitClosureReference(this);
142  }
143
144  /**
145   * {@inheritDoc}
146   */
147  @Override
148  public void walk(GoloIrVisitor visitor) {
149    target.accept(visitor);
150  }
151
152  /**
153   * {@inheritDoc}
154   */
155  @Override
156  public List<GoloElement<?>> children() {
157    return target.children();
158  }
159
160
161  /**
162   * {@inheritDoc}
163   */
164  @Override
165  protected void replaceElement(GoloElement<?> original, GoloElement<?> newElement) {
166    if (newElement instanceof GoloFunction && target.equals(original)) {
167      setTarget((GoloFunction) newElement);
168    } else {
169      throw cantReplace(original, newElement);
170    }
171  }
172
173  @Override
174  public String toString() {
175    return String.format("ClosureReference{target=%s, captured=%s}", target, getCapturedReferenceNames());
176  }
177}