001/*
002 * Copyright (c) 2012-2017 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 */
009
010package org.eclipse.golo.compiler.ir;
011
012import java.util.List;
013import java.util.LinkedList;
014import java.util.Objects;
015import org.eclipse.golo.compiler.parser.GoloASTNode;
016
017import static java.util.Collections.unmodifiableList;
018
019public final class ForEachLoopStatement extends GoloStatement implements Scope, BlockContainer {
020  private Block block = Block.emptyBlock();
021  private ExpressionStatement iterable;
022  private final List<LocalReference> valueRefs = new LinkedList<>();
023  private ExpressionStatement whenClause;
024  private boolean isVarargs = false;
025
026  ForEachLoopStatement() {
027    super();
028  }
029
030  public ForEachLoopStatement block(Object block) {
031    this.block = Builders.toBlock(block);
032    return this;
033  }
034
035  @Override
036  public ForEachLoopStatement ofAST(GoloASTNode node) {
037    node.setIrElement(this);
038    return this;
039  }
040
041  public ForEachLoopStatement on(Object iterable) {
042    this.iterable = ExpressionStatement.of(iterable);
043    return this;
044  }
045
046  public ForEachLoopStatement varargs(boolean b) {
047    this.isVarargs = b;
048    return this;
049  }
050
051  public ForEachLoopStatement var(Object varRef) {
052    LocalReference ref;
053    if (varRef instanceof String) {
054      ref = Builders.localRef(varRef).variable();
055    } else if (varRef instanceof LocalReference) {
056      ref = (LocalReference) varRef;
057    } else {
058      throw new IllegalArgumentException("not a ref, a string or a builder");
059    }
060    this.valueRefs.add(ref);
061    return this;
062  }
063
064  public ForEachLoopStatement when(Object clause) {
065    this.whenClause = ExpressionStatement.of(clause);
066    return this;
067  }
068
069  public ExpressionStatement getIterable() {
070    return iterable;
071  }
072
073  public Block getBlock() {
074    return block;
075  }
076
077  public boolean isDestructuring() {
078    return valueRefs.size() > 1;
079  }
080
081  public boolean isVarargs() {
082    return this.isVarargs;
083  }
084
085  public LocalReference getReference() {
086    return valueRefs.get(0);
087  }
088
089  public List<LocalReference> getReferences() {
090    return unmodifiableList(valueRefs);
091  }
092
093  public boolean hasWhenClause() {
094    return whenClause != null;
095  }
096
097  public ExpressionStatement getWhenClause() {
098    return whenClause;
099  }
100
101  @Override
102  public void relink(ReferenceTable table) {
103    block.relink(table);
104  }
105
106  @Override
107  public void relinkTopLevel(ReferenceTable table) {
108    block.relinkTopLevel(table);
109  }
110
111  @Override
112  public void accept(GoloIrVisitor visitor) {
113    visitor.visitForEachLoopStatement(this);
114  }
115
116  @Override
117  public void walk(GoloIrVisitor visitor) {
118    for (LocalReference ref : valueRefs) {
119      ref.accept(visitor);
120    }
121    iterable.accept(visitor);
122    if (whenClause != null) {
123      whenClause.accept(visitor);
124    }
125    block.accept(visitor);
126  }
127
128  @Override
129  protected void replaceElement(GoloElement original, GoloElement newElement) {
130    if (Objects.equals(iterable, original)) {
131      on(newElement);
132    } else if (Objects.equals(whenClause, original)) {
133      when(newElement);
134    } else if (Objects.equals(block, original)) {
135      block(newElement);
136    } else {
137      throw cantReplace(original, newElement);
138    }
139  }
140}