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.LinkedList; 014 015public abstract class ExpressionStatement<T extends ExpressionStatement<T>> extends GoloStatement<T> { 016 017 private final LinkedList<GoloAssignment<?>> declarations = new LinkedList<>(); 018 019 /** 020 * Defines a variable declaration (assignment) local to this expression. 021 */ 022 public T with(Object a) { 023 if (!(a instanceof GoloAssignment)) { 024 throw new IllegalArgumentException(("Must be an assignment, got " + a)); 025 } 026 GoloAssignment<?> declaration = (GoloAssignment<?>) a; 027 declarations.add(declaration.declaring()); 028 makeParentOf(declaration); 029 return self(); 030 } 031 032 /** 033 * Returns the local declarations of this expression if any. 034 */ 035 public GoloAssignment<?>[] declarations() { 036 return declarations.toArray(new GoloAssignment<?>[declarations.size()]); 037 } 038 039 /** 040 * Checks if this expression has local variable declarations. 041 */ 042 public boolean hasLocalDeclarations() { 043 return !declarations.isEmpty(); 044 } 045 046 /** 047 * Removes all local declarations. 048 */ 049 public void clearDeclarations() { 050 declarations.clear(); 051 } 052 053 /** 054 * Creates an binary operation representing the anonymous call on this expression. 055 * 056 * <p>For instance, code such as: 057 * <pre class="listing"><code class="lang-golo" data-lang="golo"> 058 * (|x| -> x + 2)(40) 059 * </code></pre> 060 * actually creates a {@link BinaryOperation} or type {@link OperatorType#ANON_CALL} 061 * whose first argument is a {@code ClosureReference} and the second one a {@link FunctionInvocation} holding the 062 * argument. 063 * 064 * <p>This method ease the creation of such a node. 065 * This expression must return a {@link gololang.FunctionReference} when evaluated. This is <em>not checked</em>. 066 * 067 * <p>For instance, in code like 068 * <pre class="listing"><code class="lang-golo" data-lang="golo"> 069 * let f = |x| -> |y| -> x * y 070 * f(2)(42) 071 * </code></pre> 072 * the call is an anonymous call between {@code f(2)} and {@code (42)}, and can be generated by: 073 * <pre class="listing"><code class="lang-java" data-lang="java"> 074 * call("f").withArgs(constant(2)).call(constant(42)) 075 * </pre></code> 076 * <p>See also the 077 * <a href="http://golo-lang.org/documentation/next/#_calling_functions_that_return_functions"> 078 * Golo guide</a>. 079 */ 080 public BinaryOperation call(Object... arguments) { 081 FunctionInvocation invocation; 082 if (arguments.length == 1 && arguments[0] instanceof FunctionInvocation) { 083 invocation = (FunctionInvocation) arguments[0]; 084 if (!invocation.isAnonymous()) { 085 throw new IllegalArgumentException("Invocation in anonymous calls must be anonymous."); 086 } 087 } else { 088 invocation = FunctionInvocation.of(null).withArgs(arguments); 089 } 090 return BinaryOperation.create(OperatorType.ANON_CALL, this, invocation); 091 } 092 093 /** 094 * Expression coercion. 095 * 096 * <p>If the given value is an expression, casts it. If it's a literal value, returns a {@code ConstantStatement}. 097 * If it's a {@link LocalReference}, creates a {@link ReferenceLookup} from it. 098 * 099 * @see ConstantStatement#isLiteralValue(Object) 100 */ 101 public static ExpressionStatement<?> of(Object expr) { 102 if (expr instanceof ExpressionStatement) { 103 return (ExpressionStatement<?>) expr; 104 } 105 if (ConstantStatement.isLiteralValue(expr)) { 106 return ConstantStatement.of(expr); 107 } 108 if (expr instanceof LocalReference) { 109 return ((LocalReference) expr).lookup(); 110 } 111 throw cantConvert("ExpressionStatement", expr); 112 } 113}