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.lang.reflect.Method; 014 015/** 016 * Represents a function call. 017 */ 018public final class FunctionInvocation extends AbstractInvocation<FunctionInvocation> { 019 020 private boolean onReference = false; 021 private boolean onModuleState = false; 022 private boolean anonymous = false; 023 private boolean constant = false; 024 025 private FunctionInvocation() { 026 super("anonymous"); 027 anonymous = true; 028 } 029 030 private FunctionInvocation(String name) { 031 super(name); 032 } 033 034 /** 035 * Full function invocation creation in one call. 036 * <p> 037 * A lot less readable than the fluent API, but useful when doing meta-generation 038 * 039 * @param name the name of the function to call 040 * @param onReference tells if the call is on a reference 041 * @param onModuleState tells if the call in on a module level variable 042 * @param constant tells if the call is constant (banged) 043 * @param args the call arguments 044 * @return the fully built corresponding invocation 045 * @see #of(Object) 046 */ 047 public static FunctionInvocation create(String name, boolean onReference, boolean onModuleState, boolean constant, Object... args) { 048 return of(name) 049 .onReference(onReference) 050 .onModuleState(onModuleState) 051 .constant(constant) 052 .withArgs(args); 053 } 054 055 056 /** 057 * Calls a function by name. 058 * 059 * <p>Typical usage: 060 * <pre class="listing"><code class="lang-java" data-lang="java"> 061 * FunctionInvocation.of("foo").withArgs(constant("answer "), constant(42)) 062 * </code></pre> 063 * creates 064 * <pre class="listing"><code class="lang-golo" data-lang="golo"> 065 * foo("answer ", 42) 066 * </code></pre> 067 * 068 * @param name the name of the function to call, a {@link GoloFunction}, a {@link ReferenceLookup} or a {@code java.lang.reflect.Method} 069 * @return the corresponding invocation 070 */ 071 public static FunctionInvocation of(Object name) { 072 if (name == null || "".equals(name)) { 073 return new FunctionInvocation(); 074 } 075 if (name instanceof FunctionInvocation) { 076 return (FunctionInvocation) name; 077 } 078 if (name instanceof GoloFunction) { 079 return new FunctionInvocation(((GoloFunction) name).getName()); 080 } 081 if (name instanceof Method) { 082 Method m = (Method) name; 083 return new FunctionInvocation(m.getDeclaringClass().getCanonicalName() + "." + m.getName()); 084 } 085 if (name instanceof ReferenceLookup) { 086 return new FunctionInvocation(((ReferenceLookup) name).getName()).onReference(true); 087 } 088 return new FunctionInvocation(name.toString()); 089 } 090 091 protected FunctionInvocation self() { return this; } 092 093 /** 094 * Define this call as being on a reference or not. 095 * 096 * <p>For instance in: 097 * <pre class="listing"><code class="lang-golo" data-lang="golo"> 098 * let f = |x| -> x + 2 099 * f(40) 100 * </code></pre> 101 * the call to {@code f} is on a reference. 102 */ 103 public FunctionInvocation onReference(boolean isOnReference) { 104 this.onReference = isOnReference; 105 return this; 106 } 107 108 /** 109 * Define this call as being on a reference. 110 * 111 * Same as {@code onReference(true)}. 112 */ 113 public FunctionInvocation onReference() { 114 return onReference(true); 115 } 116 117 public boolean isOnReference() { 118 return onReference; 119 } 120 121 /** 122 * Checks if this call is anonymous. 123 * 124 * <p>For instance, in: 125 * <pre class="listing"><code class="lang-golo" data-lang="golo"> 126 * f("answer")(42) 127 * </code></pre> 128 * the call with {@code 42} is an anonymous one. 129 */ 130 public boolean isAnonymous() { 131 return anonymous; 132 } 133 134 public FunctionInvocation onModuleState(boolean isOnModuleState) { 135 this.onModuleState = isOnModuleState; 136 return this; 137 } 138 139 public FunctionInvocation onModuleState() { 140 return onModuleState(true); 141 } 142 143 public boolean isOnModuleState() { 144 return onModuleState; 145 } 146 147 public FunctionInvocation constant(boolean isConstant) { 148 this.constant = isConstant; 149 return this; 150 } 151 152 public FunctionInvocation constant() { 153 return this.constant(true); 154 } 155 156 public boolean isConstant() { 157 return constant; 158 } 159 160 protected FunctionInvocation copy() { 161 return create(anonymous ? null : getName(), 162 onReference, onModuleState, constant, getArguments().toArray()); 163 } 164 165 /** 166 * {@inheritDoc} 167 */ 168 @Override 169 public FunctionInvocation withArgs(Object... arguments) { 170 super.withArgs(arguments); 171 return this; 172 } 173 174 /** 175 * {@inheritDoc} 176 */ 177 @Override 178 public String toString() { 179 return String.format("FunctionInvocation{name=%s, arity=%s}", getName(), getArity()); 180 } 181 182 /** 183 * {@inheritDoc} 184 */ 185 @Override 186 public void accept(GoloIrVisitor visitor) { 187 visitor.visitFunctionInvocation(this); 188 } 189}