/*
* $Id$
*
* SARL is an general-purpose agent programming language.
* More details on http://www.sarl.io
*
* Copyright (C) 2014-2017 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.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.inject.Inject;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtend.core.xtend.XtendMember;
import org.eclipse.xtext.common.types.JvmConstructor;
import org.eclipse.xtext.common.types.JvmOperation;
import org.eclipse.xtext.util.JavaVersion;
import org.eclipse.xtext.xbase.compiler.GeneratorConfig;
import org.eclipse.xtext.xbase.compiler.IGeneratorConfigProvider;
import org.eclipse.xtext.xbase.compiler.output.ITreeAppendable;
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
import org.eclipse.xtext.xbase.lib.Pair;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import io.sarl.lang.SARLVersion;
import io.sarl.lang.actionprototype.ActionParameterTypes;
import io.sarl.lang.actionprototype.ActionPrototype;
import io.sarl.lang.generator.GeneratorConfig2;
import io.sarl.lang.generator.IGeneratorConfigProvider2;
import io.sarl.lang.sarl.SarlBehaviorUnit;
/** Describe generation context.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
abstract class GenerationContext {
private final String identifier;
/** Compute serial number for serializable objects.
*/
private long serial = 1L;
/** Index of the late generated action.
*/
private int actionIndex;
/** Index of the late generated behavior unit.
*/
private int behaviorUnitIndex;
/** Index of the late generated localType.
*/
private int localTypeIndex;
/** Set of capacities for which a capacuty-use field was generated.
*/
private final Set<String> generatedCapacityUseFields = CollectionLiterals.<String>newHashSet();
/** collection of the generated constructors.
*/
@SuppressWarnings("unchecked")
private final Map<ActionParameterTypes, JvmConstructor> generatedConstructors = CollectionLiterals.newTreeMap(null);
/** Collection of the inherited final operations.
*/
@SuppressWarnings("unchecked")
private final Map<ActionPrototype, JvmOperation> finalOperations = CollectionLiterals.newTreeMap(null);
/** Collection of the inherited overridable operations.
*/
@SuppressWarnings("unchecked")
private final Map<ActionPrototype, JvmOperation> overridableOperations = CollectionLiterals.newTreeMap(null);
/** Collection of the inherited operations that have not been implemented.
*/
@SuppressWarnings("unchecked")
private final Map<ActionPrototype, JvmOperation> operationsToImplement = CollectionLiterals.newTreeMap(null);
/** List of elements that must be generated at the end of the generation process.
*/
private final List<Runnable> preFinalization = CollectionLiterals.newLinkedList();
/** List of elements that must be generated after the generation process.
*/
private final List<Runnable> postFinalization = CollectionLiterals.newLinkedList();
/** Guard evaluators to generate. The keys are the event identifiers. The values are the code snipsets for
* evaluating guards and returning the event handler runnables.
*/
@SuppressWarnings("unchecked")
private final Map<String, Pair<SarlBehaviorUnit, Collection<Procedure1<ITreeAppendable>>>> guardEvaluators
= CollectionLiterals.newHashMap();
/** The context object.
*/
private final EObject contextObject;
/** The provider of generation configuration.
*/
@Inject
private IGeneratorConfigProvider generatorConfigProvider;
/** The provider of generation configuration v2.
*/
@Inject
private IGeneratorConfigProvider2 generatorConfigProvider2;
/** Buffering the current generator configuration.
*/
private GeneratorConfig generatorConfig;
/** Buffering the current generator configuration v2.
*/
private GeneratorConfig2 generatorConfig2;
/** Parent context.
*/
private GenerationContext parent;
/** Construct a information about the generation.
*
* @param owner the object for which the context is created.
* @param identifier the identifier of the type for which the context is opened.
*/
GenerationContext(EObject owner, String identifier) {
this.identifier = identifier;
this.contextObject = owner;
}
@Override
public String toString() {
return "Generation context for: " + getTypeIdentifier(); //$NON-NLS-1$
}
/** Replies the parent context if any.
*
* @return the parent context or {@code null}.
* @since 0.5
*/
public GenerationContext getParentContext() {
return this.parent;
}
/** Change the parent context if any.
*
* @param parent the parent context or {@code null}.
* @since 0.5
*/
public void setParentContext(GenerationContext parent) {
this.parent = parent;
}
/** Replies the identifier of the associated type.
*
* @return the identifier of the context's type.
*/
public String getTypeIdentifier() {
return this.identifier;
}
/** Replies the generator configuration.
*
* @return the configuration.
*/
public GeneratorConfig getGeneratorConfig() {
if (this.generatorConfig == null) {
this.generatorConfig = this.generatorConfigProvider.get(
EcoreUtil.getRootContainer(this.contextObject));
}
return this.generatorConfig;
}
/** Replies the generator configuration v2.
*
* @return the configuration.
*/
public GeneratorConfig2 getGeneratorConfig2() {
if (this.generatorConfig2 == null) {
this.generatorConfig2 = this.generatorConfigProvider2.get(
EcoreUtil.getRootContainer(this.contextObject));
}
return this.generatorConfig2;
}
/** Replies the guard evaluation code for the given event.
*
* @return the guard evaluators.
*/
public Collection<Pair<SarlBehaviorUnit, Collection<Procedure1<ITreeAppendable>>>>
getGuardEvaluationCodes() {
return this.guardEvaluators.values();
}
/** Replies the guard evaluation code for the given event.
*
* @param source the source of the guard evaluation.
* @return the guard evaluators.
*/
public Collection<Procedure1<ITreeAppendable>> getGuardEvalationCodeFor(SarlBehaviorUnit source) {
assert source != null;
final String id = source.getName().getIdentifier();
final Collection<Procedure1<ITreeAppendable>> evaluators;
final Pair<SarlBehaviorUnit, Collection<Procedure1<ITreeAppendable>>> pair = this.guardEvaluators.get(id);
if (pair == null) {
evaluators = new ArrayList<>();
this.guardEvaluators.put(id, new Pair<>(source, evaluators));
} else {
evaluators = pair.getValue();
assert evaluators != null;
}
return evaluators;
}
/** Replies the computed serial number.
*
* @return the serial number.
*/
public long getSerial() {
return this.serial;
}
/** Increment the serial number by the given ammount.
*
* @param value the value to add to the serial number.
*/
public void incrementSerial(long value) {
this.serial += value;
}
/** Replies if a constructor is generated.
*
* @return <code>true</code> if the constructor is generated; <code>false</code> if created.
*/
public boolean hasConstructor() {
return !this.generatedConstructors.isEmpty();
}
/** Add a generated constructor into the context.
*
* @param parameters the specification of the parameters of the constructor.
* @param jvmElement the generated element.
*/
public void addGeneratedConstructor(ActionParameterTypes parameters, JvmConstructor jvmElement) {
this.generatedConstructors.put(parameters, jvmElement);
}
/** Replies the collection of the generated constructor.
*
* @return the original collection of constructors.
*/
public Map<ActionParameterTypes, JvmConstructor> getGeneratedConstructors() {
return this.generatedConstructors;
}
/** Add a capacity for which a capacity-use field is generated.
*
* @param capacity the identifier of the capacity.
*/
public void addGeneratedCapacityUseField(String capacity) {
this.generatedCapacityUseFields.add(capacity);
}
/** Replies the capacities for which capacity-use fields are generated.
*
* @return the capacity identifiers.
*/
public Set<String> getGeneratedCapacityUseFields() {
return this.generatedCapacityUseFields;
}
/** Replies the collection of the inherited final operations.
*
* @return the original collection of operations.
*/
public Map<ActionPrototype, JvmOperation> getInheritedFinalOperations() {
return this.finalOperations;
}
/** Replies the collection of the inherited overridable operations.
*
* @return the original collection of operations.
*/
public Map<ActionPrototype, JvmOperation> getInheritedOverridableOperations() {
return this.overridableOperations;
}
/** Replies the collection of the inherited operations that are not yet implemented.
*
* @return the original collection of operations.
*/
public Map<ActionPrototype, JvmOperation> getInheritedOperationsToImplement() {
return this.operationsToImplement;
}
/** Replies the collection of the elements that must be generated at the end of
* the generation process.
*
* <p>The differed generation element are the element's components that should be
* created after all the elements from the SARL input. The runnable codes
* are run at the end of the JVM element generation.
*
* @return the original collection of elements.
* @since 0.5
*/
public List<Runnable> getPreFinalizationElements() {
return this.preFinalization;
}
/** Replies the collection of the elements that must be generated after
* the generation process of the current SARL element.
*
* <p>The differed generation element are the element's components that could be
* generated after the complete JVM type is generated. They are extended the
* JVM type definition with additionnal elements (annotations...)
*
* @return the original collection of elements.
* @since 0.5
*/
public List<Runnable> getPostFinalizationElements() {
final GenerationContext prt = getParentContext();
if (prt != null) {
return prt.getPostFinalizationElements();
}
return this.postFinalization;
}
/** Replies the index of the late created action.
*
* @return the index.
*/
public int getActionIndex() {
return this.actionIndex;
}
/** Set the index of the late created action.
*
* @param index the index.
*/
public void setActionIndex(int index) {
this.actionIndex = index;
}
/** Replies the index of the last created behavior unit.
*
* @return the index
*/
public int getBehaviorUnitIndex() {
return this.behaviorUnitIndex;
}
/** Replies the index of the last created behavior unit.
*
* @param index the index.
*/
public void setBehaviorUnitIndex(int index) {
this.behaviorUnitIndex = index;
}
/** Replies the index of the late created local type.
*
* @return the index.
*/
public int getLocalTypeIndex() {
return this.localTypeIndex;
}
/** Set the index of the late created local type.
*
* @param index the index.
*/
public void setLocalTypeIndex(int index) {
this.localTypeIndex = index;
}
/** Replies if the given member is supported in the current context.
*
* @param member the member to test.
* @return <code>true</code> if the member is supported, <code>false</code> for ignoring it.
*/
public abstract boolean isSupportedMember(XtendMember member);
/** Replies if the compiler is using Java8 or higher.
*
* @return <code>true</code> if the compiler uses Java8 or higher. Otherwise <code>false</code>.
*/
public boolean isAtLeastJava8() {
final JavaVersion javaVersion = JavaVersion.fromQualifier(SARLVersion.MINIMAL_JDK_VERSION);
return javaVersion != null && getGeneratorConfig().getJavaSourceVersion().isAtLeast(javaVersion);
}
}