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.LinkedList; 013import java.util.List; 014import java.util.Optional; 015 016import org.eclipse.golo.compiler.parser.GoloASTNode; 017 018import static java.util.Collections.unmodifiableList; 019import static org.eclipse.golo.compiler.ir.Builders.*; 020import static java.util.Objects.requireNonNull; 021 022public final class Block extends ExpressionStatement implements Scope { 023 private final List<GoloStatement> statements = new LinkedList<>(); 024 private ReferenceTable referenceTable; 025 private boolean hasReturn = false; 026 027 Block(ReferenceTable referenceTable) { 028 super(); 029 this.referenceTable = referenceTable; 030 } 031 032 public static Block emptyBlock() { 033 return new Block(new ReferenceTable()); 034 } 035 036 public static Block of(Object block) { 037 if (block == null) { 038 return emptyBlock(); 039 } 040 if (block instanceof Block) { 041 return (Block) block; 042 } 043 throw cantConvert("Block", block); 044 } 045 046 @Override 047 public Block ofAST(GoloASTNode n) { 048 super.ofAST(n); 049 return this; 050 } 051 052 public void merge(Block other) { 053 for (GoloStatement innerStatement : other.getStatements()) { 054 this.addStatement(innerStatement); 055 } 056 } 057 058 public ReferenceTable getReferenceTable() { 059 return referenceTable; 060 } 061 062 @Override 063 public Optional<ReferenceTable> getLocalReferenceTable() { 064 return Optional.of(referenceTable); 065 } 066 067 public Block ref(Object referenceTable) { 068 if (referenceTable instanceof ReferenceTable) { 069 setReferenceTable((ReferenceTable) referenceTable); 070 return this; 071 } 072 throw new IllegalArgumentException("not a reference table"); 073 } 074 075 public void setReferenceTable(ReferenceTable referenceTable) { 076 this.referenceTable = requireNonNull(referenceTable); 077 } 078 079 public void internReferenceTable() { 080 this.referenceTable = referenceTable.flatDeepCopy(true); 081 } 082 083 public List<GoloStatement> getStatements() { 084 return unmodifiableList(statements); 085 } 086 087 public Block add(Object statement) { 088 this.addStatement(toGoloStatement(statement)); 089 return this; 090 } 091 092 private void updateStateWith(GoloStatement statement) { 093 referenceTable.updateFrom(statement); 094 makeParentOf(statement); 095 checkForReturns(statement); 096 } 097 098 public void addStatement(GoloStatement statement) { 099 statements.add(statement); 100 updateStateWith(statement); 101 } 102 103 public void prependStatement(GoloStatement statement) { 104 statements.add(0, statement); 105 updateStateWith(statement); 106 } 107 108 private void setStatement(int idx, GoloStatement statement) { 109 statements.set(idx, statement); 110 updateStateWith(statement); 111 } 112 113 private void checkForReturns(GoloStatement statement) { 114 if (statement instanceof ReturnStatement || statement instanceof ThrowStatement) { 115 hasReturn = true; 116 } else if (statement instanceof ConditionalBranching) { 117 hasReturn = hasReturn || ((ConditionalBranching) statement).returnsFromBothBranches(); 118 } 119 } 120 121 public boolean hasReturn() { 122 return hasReturn; 123 } 124 125 public int size() { 126 return statements.size(); 127 } 128 129 public boolean hasOnlyReturn() { 130 return statements.size() == 1 131 && statements.get(0) instanceof ReturnStatement 132 && !((ReturnStatement) statements.get(0)).isReturningVoid(); 133 } 134 135 @Override 136 public String toString() { 137 return "{" + statements.toString() + "}"; 138 } 139 140 public boolean isEmpty() { 141 return statements.isEmpty(); 142 } 143 144 @Override 145 public void relink(ReferenceTable table) { 146 this.referenceTable.relink(table); 147 } 148 149 @Override 150 public void relinkTopLevel(ReferenceTable table) { 151 this.referenceTable.relinkTopLevel(table); 152 } 153 154 @Override 155 public void accept(GoloIrVisitor visitor) { 156 visitor.visitBlock(this); 157 } 158 159 @Override 160 public void walk(GoloIrVisitor visitor) { 161 for (LocalReference ref : referenceTable.ownedReferences()) { 162 ref.accept(visitor); 163 } 164 for (GoloStatement statement : statements) { 165 statement.accept(visitor); 166 } 167 } 168 169 @Override 170 protected void replaceElement(GoloElement original, GoloElement newElement) { 171 if (statements.contains(original) && newElement instanceof GoloStatement) { 172 setStatement(statements.indexOf(original), (GoloStatement) newElement); 173 } else { 174 throw cantReplace(original, newElement); 175 } 176 } 177}