Skip to content

Commit

Permalink
[lang] Enable static and not static features into the formal paramete…
Browse files Browse the repository at this point in the history
…r's default values.

see #612

Signed-off-by: Stéphane Galland <galland@arakhne.org>
  • Loading branch information
gallandarakhneorg committed Apr 24, 2021
1 parent af0faef commit 6dbc11c
Show file tree
Hide file tree
Showing 19 changed files with 3,286 additions and 95 deletions.
Expand Up @@ -37,6 +37,7 @@
import org.eclipse.xtext.xbase.lib.Pure;

import io.sarl.lang.SARLConfig;
import io.sarl.lang.jvmmodel.IDefaultValueAccessDetector;
import io.sarl.lang.jvmmodel.SARLJvmModelInferrer;
import io.sarl.lang.typesystem.IOperationHelper;
import io.sarl.lang.util.Utils;
Expand Down Expand Up @@ -77,9 +78,23 @@ public class SARLJvmGenerator extends XtendGenerator {
@Inject
private IResourceTypeDetector resourceTypeDetector;

@Inject
private IDefaultValueAccessDetector defaultValueAccessDetector;

@Override
protected ITreeAppendable _generateModifier(JvmOperation it, ITreeAppendable appendable, GeneratorConfig config) {
if (Utils.isDynamicDefaultValueFunctionName(it.getSimpleName())) {
// The operation is dedicated to the support of a dynamic and instance based default value.
if (this.defaultValueAccessDetector.isStaticAccess(it)) {
it.setStatic(true);
}
}
return super._generateModifier(it, appendable, config);
}

@Override
protected ITreeAppendable _generateMember(JvmOperation it, ITreeAppendable appendable, GeneratorConfig config) {
if (Utils.STATIC_CONSTRUCTOR_NAME.equals(it.getSimpleName())) {
if (Utils.isStaticConstructorName(it.getSimpleName())) {
// The constructor name is not the same as the declaring type.
// We assume that the constructor is a static constructor.
return generateStaticConstructor(it, appendable, config);
Expand Down
@@ -0,0 +1,103 @@
/*
* $Id$
*
* SARL is an general-purpose agent programming language.
* More details on http://www.sarl.io
*
* Copyright (C) 2014-2021 the original authors or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.sarl.lang.jvmmodel;

import java.util.List;

import com.google.inject.Inject;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.common.types.JvmConstructor;
import org.eclipse.xtext.common.types.JvmExecutable;
import org.eclipse.xtext.common.types.JvmField;
import org.eclipse.xtext.common.types.JvmGenericType;
import org.eclipse.xtext.common.types.JvmIdentifiableElement;
import org.eclipse.xtext.common.types.JvmOperation;
import org.eclipse.xtext.xbase.XAbstractFeatureCall;
import org.eclipse.xtext.xbase.XExpression;
import org.eclipse.xtext.xbase.XFeatureCall;
import org.eclipse.xtext.xbase.XMemberFeatureCall;
import org.eclipse.xtext.xbase.jvmmodel.ILogicalContainerProvider;

/** Detector of the type of access to the default value of a formal parameter.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @since 0.12
*/
public class DefaultValueAccessDetector implements IDefaultValueAccessDetector {

@Inject
private ILogicalContainerProvider logicalContainerProvider;

@Override
public boolean isStaticFieldStorage(EObject sourceObject, XExpression defaultValue, JvmExecutable parameterContainer, JvmGenericType executableContainer) {
if (executableContainer.isInterface()) {
return true;
}
if (parameterContainer instanceof JvmConstructor) {
return true;
}
if (defaultValue instanceof XFeatureCall || defaultValue instanceof XMemberFeatureCall) {
return false;
}
final List<XAbstractFeatureCall> calls = EcoreUtil2.getAllContentsOfType(defaultValue, XAbstractFeatureCall.class);
for (final XAbstractFeatureCall call : calls) {
if (call instanceof XFeatureCall || call instanceof XMemberFeatureCall) {
return false;
}
}
return true;
}

@Override
@SuppressWarnings("checkstyle:nestedifdepth")
public boolean isStaticAccess(JvmOperation operation) {
if (!operation.isStatic() && operation.getDeclaringType() instanceof JvmGenericType) {
final JvmGenericType type = (JvmGenericType) operation.getDeclaringType();
if (!type.isInterface()) {
final XExpression body = this.logicalContainerProvider.getAssociatedExpression(operation);
if (body != null) {
final List<XAbstractFeatureCall> calls = EcoreUtil2.getAllContentsOfType(body, XAbstractFeatureCall.class);
if (body instanceof XAbstractFeatureCall) {
calls.add(0, (XAbstractFeatureCall) body);
}
for (final XAbstractFeatureCall call : calls) {
if (call instanceof XMemberFeatureCall || call instanceof XFeatureCall) {
final JvmIdentifiableElement feature = call.getFeature();
if (feature instanceof JvmField && !((JvmField) feature).isStatic()) {
return false;
}
if (feature instanceof JvmOperation && !((JvmOperation) feature).isStatic()) {
return false;
}
}
}
}
}
}
return true;
}

}
Expand Up @@ -474,6 +474,16 @@ public void release() {
this.guardEvaluators.clear();
}

/** Replies the context object.
*
* @return the context object.
* @since 0.12
*/
@Pure
public EObject getContextObject() {
return this.contextObject;
}

/** Replies if the generated type is injectable.
*
* @return {@code true} if the generated type is injectable.
Expand Down
@@ -0,0 +1,59 @@
/*
* $Id$
*
* SARL is an general-purpose agent programming language.
* More details on http://www.sarl.io
*
* Copyright (C) 2014-2021 the original authors or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.sarl.lang.jvmmodel;

import com.google.inject.ImplementedBy;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.common.types.JvmExecutable;
import org.eclipse.xtext.common.types.JvmGenericType;
import org.eclipse.xtext.common.types.JvmOperation;
import org.eclipse.xtext.xbase.XExpression;

/** Detector of the type of access to the default value of a formal parameter.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @since 0.12
*/
@ImplementedBy(DefaultValueAccessDetector.class)
public interface IDefaultValueAccessDetector {

/** Replies if the given default value should be stored into a static field.
*
* @param sourceObject the source of the generation.
* @param defaultValue the default value to test.
* @param parameterContainer the container of the formal parameter.
* @param executableContainer the container of the executable.
* @return {@code true} if the default value should be stored into a static field.
*/
boolean isStaticFieldStorage(EObject sourceObject, XExpression defaultValue, JvmExecutable parameterContainer, JvmGenericType executableContainer);

/** Replies if the given operation is a default-value operation that contains only references to static features.
*
* @param operation the operation to test.
* @return {@code true} if the default value should be accessed statically.
*/
boolean isStaticAccess(JvmOperation operation);

}
Expand Up @@ -180,6 +180,7 @@
import io.sarl.lang.sarl.SarlSpace;
import io.sarl.lang.sarl.actionprototype.ActionParameterTypes;
import io.sarl.lang.sarl.actionprototype.ActionPrototype;
import io.sarl.lang.sarl.actionprototype.DynamicArgumentName;
import io.sarl.lang.sarl.actionprototype.IActionPrototypeProvider;
import io.sarl.lang.sarl.actionprototype.InferredPrototype;
import io.sarl.lang.sarl.actionprototype.InferredStandardParameter;
Expand Down Expand Up @@ -345,6 +346,9 @@ public class SARLJvmModelInferrer extends XtendJvmModelInferrer {
@Inject
private IDefaultVisibilityProvider defaultVisibilityProvider;

@Inject
private IDefaultValueAccessDetector defaultValueAccessDetector;

/** Generation contexts.
*/
private LinkedList<GenerationContext> bufferedContexes = new LinkedList<>();
Expand Down Expand Up @@ -1535,7 +1539,7 @@ protected void transform(final XtendConstructor source, final JvmGenericType con
final JvmOperation staticConstructor = this.typesFactory.createJvmOperation();
container.getMembers().add(staticConstructor);
this.associator.associatePrimary(source, staticConstructor);
staticConstructor.setSimpleName(Utils.STATIC_CONSTRUCTOR_NAME);
staticConstructor.setSimpleName(Utils.getStaticConstructorName());
staticConstructor.setVisibility(JvmVisibility.PRIVATE);
staticConstructor.setStatic(true);
staticConstructor.setReturnType(this._typeReferenceBuilder.typeRef(Void.TYPE));
Expand Down Expand Up @@ -3220,6 +3224,7 @@ protected JvmTypeReference skipTypeParameters(JvmTypeReference type, Notifier co
* or a class (<code>false</code>).
* @param paramSpec the specification of the parameter as computed by a {@link IActionPrototypeProvider}.
*/
@SuppressWarnings("checkstyle:nestedifdepth")
protected void translateSarlFormalParameters(
GenerationContext context,
JvmExecutable owner,
Expand All @@ -3240,38 +3245,70 @@ protected void translateSarlFormalParameters(
translateParameter(owner, param);
final JvmFormalParameter lastParam = owner.getParameters().get(owner.getParameters().size() - 1);
// Treat the default value
if (i < paramSpec.size() && param instanceof SarlFormalParameter
&& ((SarlFormalParameter) param).getDefaultValue() != null) {
final XExpression defaultValue = ((SarlFormalParameter) param).getDefaultValue();
assert defaultValue != null;
hasDefaultValue = true;
final InferredStandardParameter inferredParam = paramSpec.get(i);
assert inferredParam != null;
final String namePostPart = inferredParam.getDefaultValueAnnotationValue();
final String name = this.sarlSignatureProvider.createFieldNameForDefaultValueID(namePostPart);
final JvmTypeReference fieldType = skipTypeParameters(paramType, actionContainer);
final JvmField field = this.typeBuilder.toField(defaultValue, name, fieldType, it -> {
SARLJvmModelInferrer.this.typeBuilder.setDocumentation(it,
MessageFormat.format(Messages.SARLJvmModelInferrer_11, paramName));
it.setStatic(true);
it.setFinal(true);
if (isForInterface) {
it.setVisibility(JvmVisibility.PUBLIC);
if (i < paramSpec.size() && param instanceof SarlFormalParameter) {
final SarlFormalParameter sarlParam = (SarlFormalParameter) param;
if (sarlParam.getDefaultValue() != null) {
final XExpression defaultValue = sarlParam.getDefaultValue();
assert defaultValue != null;
hasDefaultValue = true;
final InferredStandardParameter inferredParam = paramSpec.get(i);
assert inferredParam != null;
final String namePostPart = inferredParam.getDefaultValueAnnotationValue();
final JvmTypeReference inferredType = skipTypeParameters(paramType, actionContainer);
if (this.defaultValueAccessDetector.isStaticFieldStorage(sarlParam, defaultValue, owner, actionContainer)) {
//
// Generate a static definition of the default value
//
final String fieldName = this.sarlSignatureProvider.createFieldNameForDefaultValueID(namePostPart);
final JvmField field = this.typeBuilder.toField(defaultValue, fieldName, inferredType, it -> {
SARLJvmModelInferrer.this.typeBuilder.setDocumentation(it,
MessageFormat.format(Messages.SARLJvmModelInferrer_11, paramName));
it.setStatic(true);
it.setFinal(true);
if (isForInterface) {
it.setVisibility(JvmVisibility.PUBLIC);
} else {
it.setVisibility(JvmVisibility.PRIVATE);
}
SARLJvmModelInferrer.this.typeBuilder.setInitializer(it, defaultValue);
});
actionContainer.getMembers().add(field);
if (owner instanceof JvmConstructor) {
this.readAndWriteTracking.markInitialized(field, (JvmConstructor) owner);
} else {
this.readAndWriteTracking.markInitialized(field, null);
}
addAnnotationSafe(lastParam, DefaultValue.class, namePostPart);

final String rawCode = Utils.getSarlCodeFor(defaultValue);
appendGeneratedAnnotation(field, context, rawCode);
} else {
it.setVisibility(JvmVisibility.PRIVATE);
//
// Generate an instance definition of the default value
//
final String functionName = this.sarlSignatureProvider.createFunctionNameForDefaultValueID(namePostPart);
final JvmOperation method = this.typeBuilder.toMethod(defaultValue, functionName, inferredType, it -> {
SARLJvmModelInferrer.this.typeBuilder.setDocumentation(it,
MessageFormat.format(Messages.SARLJvmModelInferrer_11, paramName));
it.setReturnType(inferredType);
it.setFinal(true);
it.setVisibility(JvmVisibility.PRIVATE);
});
actionContainer.getMembers().add(method);
addAnnotationSafe(lastParam, DefaultValue.class, namePostPart);

addAnnotationSafe(method, Pure.class);

final String rawCode = Utils.getSarlCodeFor(defaultValue);
appendGeneratedAnnotation(method, context, rawCode);

setBody(method, defaultValue);

final DynamicArgumentName argument = inferredParam.getDynamicCallingArgument();
final String originalArgument = argument.getArgument();
argument.setArgument(originalArgument + "()");
}
SARLJvmModelInferrer.this.typeBuilder.setInitializer(it, defaultValue);
});
actionContainer.getMembers().add(field);
if (owner instanceof JvmConstructor) {
this.readAndWriteTracking.markInitialized(field, (JvmConstructor) owner);
} else {
this.readAndWriteTracking.markInitialized(field, null);
}
addAnnotationSafe(lastParam, DefaultValue.class, namePostPart);

final String rawCode = Utils.getSarlCodeFor(defaultValue);
appendGeneratedAnnotation(field, context, rawCode);
}
}
}
Expand Down

0 comments on commit 6dbc11c

Please sign in to comment.