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; 015 016public abstract class GoloAssignment<T extends GoloAssignment<T>> extends GoloStatement<T> implements ReferencesHolder { 017 018 private boolean declaring = false; 019 private ExpressionStatement<?> expressionStatement; 020 021 GoloAssignment() { super(); } 022 023 /** 024 * Checks if this assignment is a declaring one. 025 * 026 * @see #declaring() 027 */ 028 public final boolean isDeclaring() { 029 return declaring; 030 } 031 032 /** 033 * Defines if this assignment is a declaring one. 034 * 035 * A declaring assignment is one that first defines the value of a reference, 036 * that is a {@code let} or {@code var} assignment. An assignment to a previously defined 037 * mutable variable (one declared with {@code var}) is not a declaring assignment. 038 * 039 * <p>This is a builder method. 040 * 041 * @param isDeclaring whether the assignment is declaring. 042 * @return this assignment 043 */ 044 public final T declaring(boolean isDeclaring) { 045 this.declaring = isDeclaring; 046 return self(); 047 } 048 049 /** 050 * Makes this assignment a declaring one. 051 * <p> 052 * Same as {@code declaring(true)}. 053 * 054 * @return this assignment 055 */ 056 public final T declaring() { 057 return this.declaring(true); 058 } 059 060 /** 061 * Makes this assignment variable. 062 * 063 * @see LocalReference#variable() 064 */ 065 public abstract T variable(); 066 067 /** 068 * Checks if this assignment is constant. 069 * 070 * @see LocalReference#isConstant() 071 */ 072 public abstract boolean isConstant(); 073 074 public final ExpressionStatement<?> expression() { 075 return this.expressionStatement; 076 } 077 078 /** 079 * Defines the value to be assigned. 080 * 081 * <p>This is a builder method. 082 * 083 * @param expr the {@link ExpressionStatement} to assign or an object that can be converted into an expression 084 * @return this assignment 085 * @see ExpressionStatement#of(Object) 086 */ 087 public final T as(Object expr) { 088 this.expressionStatement = makeParentOf(ExpressionStatement.of(expr)); 089 return self(); 090 } 091 092 /** 093 * Defines the references to which assign the expression. 094 * 095 * <p>This is a builder method. 096 * <p>For instance, code like: 097 * <pre class="listing"><code class="lang-golo" data-lang="golo"> 098 * foo = 42 099 * </code></pre> 100 * can be generated by: 101 * <pre class"listing"><code class="lang-java" data-lang="java"> 102 * assign(constant(42)).to(localRef("foo")) 103 * </code></pre> 104 * or using implicit conversions: 105 * <pre class"listing"><code class="lang-java" data-lang="java"> 106 * assign(42).to("foo") 107 * </code></pre> 108 * 109 * @param refs the {@link gololang.ir.LocalReference}s to assign to 110 * @return this assignment 111 */ 112 public abstract T to(Object... refs); 113 114 115 /** 116 * {@inheritDoc} 117 */ 118 @Override 119 public LocalReference[] getDeclaringReferences() { 120 if (declaring) { 121 return getReferences(); 122 } 123 return new LocalReference[0]; 124 } 125 126 /** 127 * {@inheritDoc} 128 */ 129 @Override 130 protected void replaceElement(GoloElement<?> original, GoloElement<?> newElement) { 131 if (original.equals(expression()) && newElement instanceof ExpressionStatement) { 132 as(newElement); 133 } else { 134 throw cantReplace(original, newElement); 135 } 136 } 137 138 /** 139 * {@inheritDoc} 140 */ 141 @Override 142 public List<GoloElement<?>> children() { 143 return Collections.singletonList(expressionStatement); 144 } 145}