001/*
002 * Copyright (c) 2012-2021 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.Collections;
014import java.util.List;
015import org.eclipse.golo.runtime.InvalidDestructuringException;
016
017import static gololang.Messages.message;
018
019/**
020 * A named argument in a function call.
021 *
022 * <p>Represents nodes such as:
023 * <pre class="listing"><code class="lang-golo" data-lang="golo">
024 * foo(b=42, a=bar("answer"))
025 * </code></pre>
026 */
027public final class NamedArgument extends ExpressionStatement<NamedArgument> {
028
029  private final String name;
030  private ExpressionStatement<?> expression;
031
032  private NamedArgument(String name, ExpressionStatement<?> expression) {
033    super();
034    this.name = name;
035    this.setExpression(expression);
036  }
037
038  public static NamedArgument of(String name, Object value) {
039    return new NamedArgument(name, ExpressionStatement.of(value));
040  }
041
042  protected NamedArgument self() { return this; }
043
044  public String getName() {
045    return this.name;
046  }
047
048  public ExpressionStatement<?> expression() {
049    return this.expression;
050  }
051
052  /**
053   * Defines the value of the named argument.
054   *
055   * <p>This is a builder method.
056   *
057   * @param value the {@link ExpressionStatement} to use as the value of the argument.
058   */
059  private void setExpression(ExpressionStatement<?> value) {
060    this.expression = makeParentOf(value);
061  }
062
063  /**
064   * New style destructuring helper.
065   *
066   * <p>The destructuring must be to exactly two values. No remainer syntax is allowed.
067   * <p>The destructured values are the named and the expression.
068   *
069   * @param number number of variable that will be affected.
070   * @param substruct whether the destructuring is complete or should contains a sub structure.
071   * @param toSkip a boolean array indicating the elements to skip.
072   * @return an array containing the values to assign.
073   */
074  public Object[] __$$_destruct(int number, boolean substruct, Object[] toSkip) {
075    if (number == 2 && !substruct) {
076      return new Object[]{name, expression};
077    }
078    throw new InvalidDestructuringException("A NamedArgument must destructure to exactly two values");
079  }
080
081  /**
082   * {@inheritDoc}
083   *
084   * <p>Always throws an exception since {@link NamedArgument} can't have a local declaration.
085   */
086  @Override
087  public NamedArgument with(Object a) {
088    throw new UnsupportedOperationException(message("invalid_local_definition", this.getClass().getName()));
089  }
090
091  @Override
092  public boolean hasLocalDeclarations() {
093    return false;
094  }
095
096  /**
097   * {@inheritDoc}
098   */
099  @Override
100  public void accept(GoloIrVisitor visitor) {
101    visitor.visitNamedArgument(this);
102  }
103
104  /**
105   * {@inheritDoc}
106   */
107  @Override
108  public List<GoloElement<?>> children() {
109    return Collections.singletonList(expression);
110  }
111
112  /**
113   * {@inheritDoc}
114   */
115  @Override
116  protected void replaceElement(GoloElement<?> original, GoloElement<?> newElement) {
117    if (this.expression != original) {
118      throw doesNotContain(original);
119    }
120    this.setExpression(ExpressionStatement.of(newElement));
121  }
122}