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.List;
014import java.util.LinkedList;
015
016/**
017 * A destructuring assignment.
018 *
019 * <p>For instance:
020 * <pre class="listing"><code class="lang-golo" data-lang="golo">
021 * let a, b = [1, 2]
022 * </code></pre>
023 */
024public final class DestructuringAssignment extends GoloAssignment<DestructuringAssignment> {
025
026  private final List<LocalReference> references = new LinkedList<>();
027  private boolean isVarargs = false;
028
029  private DestructuringAssignment() {
030    super();
031  }
032
033  /**
034   * Create a destructuring assignment.
035   *
036   * <p>Typical usage:
037   * <pre class="listing"><code class="lang-java" data-lang="java">
038   * destruct(tuple(1, 2)).to("a", "b").declaring(true)
039   * </code></pre>
040   * creates
041   * <pre class="listing"><code class="lang-golo" data-lang="golo">
042   * let a, b = [1, 2]
043   * </code></pre>
044   *
045   * @param expr the expression to destructure
046   * @see #as(Object)
047   */
048  public static DestructuringAssignment destruct(Object expr) {
049    return new DestructuringAssignment().as(expr);
050  }
051
052  /**
053   * Creates a uninitialized destructuring assignment.
054   */
055  public static DestructuringAssignment create() {
056    return new DestructuringAssignment();
057  }
058
059  protected DestructuringAssignment self() { return this; }
060
061  /**
062   * Checks if this destructuring is a varargs one.
063   *
064   * @see #varargs(boolean)
065   */
066  public boolean isVarargs() {
067    return this.isVarargs;
068  }
069
070  /**
071   * Defines if this destructuring is a varargs one.
072   *
073   * <p>For instance:
074   * <pre class="listing"><code class="lang-golo" data-lang="golo">
075   * let a, b... = list[1, 2, 3, 4]
076   * </code></pre>
077   * <p>This is a builder method.
078   */
079  public DestructuringAssignment varargs(boolean varargs) {
080    this.isVarargs = varargs;
081    return this;
082  }
083
084  /**
085   * Defines this destructuring as a varargs one.
086   *
087   * <p>Same as {@code varargs(true)}.
088   */
089  public DestructuringAssignment varargs() {
090    return varargs(true);
091  }
092
093  /**
094   * {@inheritDoc}
095   */
096  @Override
097  public DestructuringAssignment variable() {
098    for (LocalReference ref : references) {
099      ref.variable();
100    }
101    return this;
102  }
103
104  /**
105   * {@inheritDoc}
106   */
107  @Override
108  public boolean isConstant() {
109    if (!references.isEmpty()) {
110      return references.get(0).isConstant();
111    }
112    return false;
113  }
114
115  /**
116   * {@inheritDoc}
117   */
118  @Override
119  public LocalReference[] getReferences() {
120    return this.references.toArray(new LocalReference[references.size()]);
121  }
122
123  /**
124   * {@inheritDoc}
125   */
126  @Override
127  public int getReferencesCount() {
128    return this.references.size();
129  }
130
131  /**
132   * @inheritDoc
133   */
134  @Override
135  public DestructuringAssignment to(Object... refs) {
136    for (Object o : refs) {
137      references.add(LocalReference.of(o));
138    }
139    return this;
140  }
141
142  @Override
143  public String toString() {
144    List<String> names = new LinkedList<>();
145    for (LocalReference r : getReferences()) {
146      names.add(r.toString());
147    }
148    return String.join(", ", names) + " = " + expression().toString();
149  }
150
151  /**
152   * {@inheritDoc}
153   */
154  @Override
155  public void accept(GoloIrVisitor visitor) {
156    visitor.visitDestructuringAssignment(this);
157  }
158
159  /**
160   * {@inheritDoc}
161   */
162  @Override
163  public void walk(GoloIrVisitor visitor) {
164    for (LocalReference ref : references) {
165      ref.accept(visitor);
166    }
167    super.walk(visitor);
168  }
169}