beginOfBlock) {
+ if (beginOfBlock != null) {
+ this.codeReceiver.append("if "); //$NON-NLS-1$
+ PyExpressionGenerator.this.generate(beginOfBlock.apply(), this.codeReceiver, this.context);
+ this.codeReceiver.append(" != None:"); //$NON-NLS-1$
+ this.codeReceiver.increaseIndentation().newLine();
+ }
+ //
+ appendCallPrefix(leftOperand, " = "); //$NON-NLS-1$
+ appendCallPrefix(receiver, "."); //$NON-NLS-1$
+ if (args != null) {
+ this.codeReceiver.append(name);
+ this.codeReceiver.append("("); //$NON-NLS-1$
+ boolean first = true;
+ for (final XExpression arg : args) {
+ if (first) {
+ first = false;
+ } else {
+ this.codeReceiver.append(", "); //$NON-NLS-1$
+ }
+ PyExpressionGenerator.this.generate(arg, this.codeReceiver, this.context);
+ }
+ this.codeReceiver.append(")"); //$NON-NLS-1$
+ } else {
+ this.codeReceiver.append(name);
+ }
+ //
+ if (beginOfBlock != null) {
+ this.codeReceiver.decreaseIndentation().newLine();
+ }
+ }
+
+ @Override
+ protected String nullKeyword() {
+ return "None"; //$NON-NLS-1$
+ }
+
+ }
+
+}
diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/PyGenerator.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/PyGenerator.java
new file mode 100644
index 0000000000..817ad28606
--- /dev/null
+++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/PyGenerator.java
@@ -0,0 +1,840 @@
+/*
+ * $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.pythongenerator.generator;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import javax.inject.Inject;
+
+import org.eclipse.xtend.core.xtend.XtendEnumLiteral;
+import org.eclipse.xtend.core.xtend.XtendExecutable;
+import org.eclipse.xtend.core.xtend.XtendMember;
+import org.eclipse.xtend.core.xtend.XtendParameter;
+import org.eclipse.xtext.common.types.JvmDeclaredType;
+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.common.types.JvmType;
+import org.eclipse.xtext.common.types.JvmTypeReference;
+import org.eclipse.xtext.common.types.TypesFactory;
+import org.eclipse.xtext.generator.IFileSystemAccess2;
+import org.eclipse.xtext.naming.QualifiedName;
+import org.eclipse.xtext.util.Strings;
+import org.eclipse.xtext.xbase.XExpression;
+import org.eclipse.xtext.xbase.compiler.ImportManager;
+import org.eclipse.xtext.xbase.lib.Pair;
+import org.eclipse.xtext.xbase.lib.Procedures.Procedure2;
+import org.eclipse.xtext.xbase.typesystem.references.LightweightTypeReference;
+
+import io.sarl.lang.actionprototype.ActionParameterTypes;
+import io.sarl.lang.actionprototype.IActionPrototypeProvider;
+import io.sarl.lang.actionprototype.InferredPrototype;
+import io.sarl.lang.actionprototype.InferredStandardParameter;
+import io.sarl.lang.actionprototype.InferredValuedParameter;
+import io.sarl.lang.actionprototype.QualifiedActionName;
+import io.sarl.lang.core.Agent;
+import io.sarl.lang.core.Behavior;
+import io.sarl.lang.core.Capacity;
+import io.sarl.lang.core.Event;
+import io.sarl.lang.core.Skill;
+import io.sarl.lang.generator.extra.AbstractExtraLanguageGenerator;
+import io.sarl.lang.generator.extra.ExtraLanguageAppendable;
+import io.sarl.lang.generator.extra.ExtraLanguageTypeConverter;
+import io.sarl.lang.generator.extra.IExtraLanguageGeneratorContext;
+import io.sarl.lang.sarl.SarlAction;
+import io.sarl.lang.sarl.SarlAgent;
+import io.sarl.lang.sarl.SarlAnnotationType;
+import io.sarl.lang.sarl.SarlBehavior;
+import io.sarl.lang.sarl.SarlBehaviorUnit;
+import io.sarl.lang.sarl.SarlCapacity;
+import io.sarl.lang.sarl.SarlCapacityUses;
+import io.sarl.lang.sarl.SarlClass;
+import io.sarl.lang.sarl.SarlConstructor;
+import io.sarl.lang.sarl.SarlEnumeration;
+import io.sarl.lang.sarl.SarlEvent;
+import io.sarl.lang.sarl.SarlField;
+import io.sarl.lang.sarl.SarlFormalParameter;
+import io.sarl.lang.sarl.SarlInterface;
+import io.sarl.lang.sarl.SarlSkill;
+import io.sarl.lang.util.Utils;
+import io.sarl.pythongenerator.PyGeneratorPlugin;
+import io.sarl.pythongenerator.configuration.PyOutputConfigurationProvider;
+
+/** The generator from SARL to the Python language.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+@SuppressWarnings("checkstyle:classfanoutcomplexity")
+public class PyGenerator extends AbstractExtraLanguageGenerator {
+
+ /** Header for a Python file.
+ */
+ public static final String PYTHON_FILE_HEADER = "#!/usr/bin/env python3"; //$NON-NLS-1$
+
+ private static final String PYTHON_FILENAME_EXTENSION = ".py"; //$NON-NLS-1$
+
+ private static final String LIBRARY_CONTENT = "__all__ = []"; //$NON-NLS-1$
+
+ private static final String LIBRARY_FILENAME = "__init__"; //$NON-NLS-1$
+
+ private static final String INSTANCE_VARIABLE_MEMENTO = "INSTANCE_VARIABLES"; //$NON-NLS-1$
+
+ private static final String EVENT_GUARDS_MEMENTO = "EVENT_GUARDS"; //$NON-NLS-1$
+
+ private PyExpressionGenerator expressionGenerator;
+
+ //----------------------------------------
+ // Utilities
+ //----------------------------------------
+
+ @Override
+ public String getPluginID() {
+ return PyGeneratorPlugin.PLUGIN_ID;
+ }
+
+ /** Replies the generator of XExpression.
+ *
+ * @param generator the generator.
+ */
+ @Inject
+ public void setExpressionGenerator(PyExpressionGenerator generator) {
+ this.expressionGenerator = generator;
+ }
+
+ /** Replies the generator of XExpression.
+ *
+ * @return the generator.
+ */
+ @Override
+ public PyExpressionGenerator getExpressionGenerator() {
+ return this.expressionGenerator;
+ }
+
+ @Override
+ protected PyAppendable createAppendable(IExtraLanguageGeneratorContext context) {
+ final ExtraLanguageTypeConverter converter = getTypeConverter(context);
+ return new PyAppendable(converter);
+ }
+
+ @Override
+ protected String getOutputConfigurationName() {
+ return PyOutputConfigurationProvider.OUTPUT_CONFIGURATION_NAME;
+ }
+
+ @Override
+ protected String getFilenameExtension() {
+ return PYTHON_FILENAME_EXTENSION;
+ }
+
+ @Override
+ protected boolean writeFile(QualifiedName name, ExtraLanguageAppendable appendable,
+ IExtraLanguageGeneratorContext context) {
+ if (super.writeFile(name, appendable, context)) {
+ // Generate the package files for the Python library
+ writePackageFiles(name, appendable.getLineSeparator(), context);
+ return true;
+ }
+ return false;
+ }
+
+ /** Generate the Python package files.
+ *
+ * This function generates the "__init__.py" files for all the packages.
+ *
+ * @param name the name of the generated type.
+ * @param lineSeparator the line separator.
+ * @param context the generation context.
+ */
+ protected void writePackageFiles(QualifiedName name, String lineSeparator,
+ IExtraLanguageGeneratorContext context) {
+ final IFileSystemAccess2 fsa = context.getFileSystemAccess();
+ final String outputConfiguration = getOutputConfigurationName();
+ QualifiedName libraryName = null;
+ for (final String segment : name.skipLast(1).getSegments()) {
+ if (libraryName == null) {
+ libraryName = QualifiedName.create(segment, LIBRARY_FILENAME);
+ } else {
+ libraryName = libraryName.append(segment).append(LIBRARY_FILENAME);
+ }
+ final String fileName = toFilename(libraryName);
+ if (!fsa.isFile(fileName)) {
+ final String content = PYTHON_FILE_HEADER + lineSeparator
+ + getGenerationComment(context) + lineSeparator
+ + LIBRARY_CONTENT;
+ if (Strings.isEmpty(outputConfiguration)) {
+ fsa.generateFile(fileName, content);
+ } else {
+ fsa.generateFile(fileName, outputConfiguration, content);
+ }
+ }
+ libraryName = libraryName.skipLast(1);
+ }
+ }
+
+ /** Replies a string representing a comment with the generation information.
+ *
+ * @param context the generation context.
+ * @return the comment text.
+ */
+ @SuppressWarnings("static-method")
+ protected String getGenerationComment(IExtraLanguageGeneratorContext context) {
+ return "# Generated by the SARL compiler the " + context.getGenerationDate().toString() //$NON-NLS-1$
+ + ". Do not change this file."; //$NON-NLS-1$
+ }
+
+ /** Generate the type declaration for a Python class.
+ *
+ * @param typeName name of the type.
+ * @param isAbstract indicates if the type is abstract (interface included).
+ * @param superTypes the super types.
+ * @param ignoreObjectType ignores the "Object" type if the super types.
+ * @param it the output.
+ * @param context the generation context.
+ * @return {@code true} if the declaration was generated. {@code false} if the declaration was not generated.
+ */
+ @SuppressWarnings("static-method")
+ protected boolean generatePythonClassDeclaration(String typeName, boolean isAbstract,
+ List extends JvmTypeReference> superTypes, boolean ignoreObjectType, PyAppendable it,
+ IExtraLanguageGeneratorContext context) {
+ if (!Strings.isEmpty(typeName)) {
+ it.append("class ").append(typeName).append("("); //$NON-NLS-1$ //$NON-NLS-2$
+ boolean isOtherSuperType = false;
+ boolean first = true;
+ for (final JvmTypeReference reference : superTypes) {
+ if (!ignoreObjectType || !Strings.equal(reference.getIdentifier(), Object.class.getName())) {
+ isOtherSuperType = true;
+ if (first) {
+ first = false;
+ } else {
+ it.append(","); //$NON-NLS-1$
+ }
+ it.append(reference.getType());
+ }
+ }
+ if (!isOtherSuperType) {
+ it.append("object"); //$NON-NLS-1$
+ }
+ it.append("):"); //$NON-NLS-1$
+ it.increaseIndentation().newLine();
+ return true;
+ }
+ return false;
+ }
+
+ /** Generate the given type.
+ *
+ * @param name the name of the type.
+ * @param isAbstract indicates if the type is abstract.
+ * @param superTypes the super types.
+ * @param ignoreObjectType ignores the "Object" type if the super types.
+ * @param members the members.
+ * @param it the output.
+ * @param context the context.
+ * @param memberGenerator the generator of members.
+ * @return {@code true} if the type declaration was generated.
+ */
+ protected boolean generateTypeDeclaration(String name, boolean isAbstract,
+ List extends JvmTypeReference> superTypes, boolean ignoreObjectType, List extends XtendMember> members, PyAppendable it,
+ IExtraLanguageGeneratorContext context, Procedure2 memberGenerator) {
+ if (!Strings.isEmpty(name)) {
+ if (!generatePythonClassDeclaration(name, isAbstract, superTypes, ignoreObjectType, it, context)
+ || context.getCancelIndicator().isCanceled()) {
+ return false;
+ }
+ //
+ it.openScope();
+ //
+ if (!generateSarlMembers(members, it, context)
+ || context.getCancelIndicator().isCanceled()) {
+ return false;
+ }
+ //
+ if (memberGenerator != null) {
+ memberGenerator.apply(it, context);
+ }
+ //
+ if (!generatePythonConstructors(members, it, context)
+ || context.getCancelIndicator().isCanceled()) {
+ return false;
+ }
+ //
+ it.decreaseIndentation().newLine().newLine();
+ //
+ it.closeScope();
+ //
+ if (context.getCancelIndicator().isCanceled()) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /** Generate the constructors for a Python class.
+ *
+ * @param members the members to be added.
+ * @param it the output.
+ * @param context the generation context.
+ * @return {@code true} if a constructor was generated. {@code false} if no constructor was generated.
+ */
+ protected boolean generatePythonConstructors(List extends XtendMember> members, PyAppendable it,
+ IExtraLanguageGeneratorContext context) {
+ // Prepare field initialization
+ boolean hasConstructor = false;
+ for (final XtendMember member : members) {
+ if (context.getCancelIndicator().isCanceled()) {
+ return false;
+ }
+ if (member instanceof SarlConstructor) {
+ hasConstructor = true;
+ generate(member, it, context);
+ it.newLine();
+ }
+ }
+ if (context.getCancelIndicator().isCanceled()) {
+ return false;
+ }
+ if (!hasConstructor) {
+ it.append("def __init__(self):"); //$NON-NLS-1$
+ it.increaseIndentation().newLine();
+ final List fields = context.getListData(INSTANCE_VARIABLE_MEMENTO, SarlField.class);
+ if (fields.isEmpty()) {
+ it.append("pass"); //$NON-NLS-1$
+ } else {
+ for (final SarlField field : fields) {
+ generatePythonField(field, it, context);
+ }
+ }
+ it.decreaseIndentation().newLine();
+ }
+ return true;
+ }
+
+ /** Create a JvmType for a Python type.
+ *
+ * @param pythonName the python type name.
+ * @return the type.
+ */
+ @SuppressWarnings("static-method")
+ protected JvmType newType(String pythonName) {
+ final JvmGenericType type = TypesFactory.eINSTANCE.createJvmGenericType();
+ final int index = pythonName.indexOf("."); //$NON-NLS-1$
+ if (index <= 0) {
+ type.setSimpleName(pythonName);
+ } else {
+ type.setPackageName(pythonName.substring(0, index - 1));
+ type.setSimpleName(pythonName.substring(index + 1));
+ }
+ return type;
+ }
+
+ /** Create a field declaration.
+ *
+ * @param field the field to generate.
+ * @param it the output
+ * @param context the generation context.
+ */
+ protected void generatePythonField(SarlField field, PyAppendable it, IExtraLanguageGeneratorContext context) {
+ if (!field.isStatic()) {
+ it.append("self."); //$NON-NLS-1$
+ }
+ final String fieldName = it.declareUniqueNameVariable(field, field.getName());
+ it.append(fieldName);
+ it.append(" = "); //$NON-NLS-1$
+ if (field.getInitialValue() != null) {
+ generate(field.getInitialValue(), null, it, context);
+ } else {
+ it.append(PyExpressionGenerator.toDefaultValue(field.getType()));
+ }
+ it.newLine();
+ }
+
+ /** Generate the Python code for an executable statement.
+ *
+ * @param name the name of the exectuable.
+ * @param executable the executable statement.
+ * @param isAbstract indicates if the executable is abstract.
+ * @param returnType the type of the value to be returned, or {@code null} if void.
+ * @param it the target for the generated content.
+ * @param context the context.
+ */
+ @SuppressWarnings({"checkstyle:npathcomplexity", "checkstyle:cyclomaticcomplexity"})
+ protected void generateExecutable(String name, XtendExecutable executable, boolean isAbstract,
+ JvmTypeReference returnType, PyAppendable it, IExtraLanguageGeneratorContext context) {
+ it.append("def ").append(name); //$NON-NLS-1$
+ it.append("(self"); //$NON-NLS-1$
+ for (final XtendParameter parameter : executable.getParameters()) {
+ it.append(", "); //$NON-NLS-1$
+ if (parameter.isVarArg()) {
+ it.append("*"); //$NON-NLS-1$
+ }
+ final String pname = it.declareUniqueNameVariable(parameter, parameter.getName());
+ it.append(pname);
+ }
+ it.append("):"); //$NON-NLS-1$
+ it.increaseIndentation().newLine();
+ if (executable.getExpression() != null) {
+ LightweightTypeReference needReturn = null;
+ if (returnType != null && !"void".equals(returnType.getIdentifier()) //$NON-NLS-1$
+ && !getEarlyExitComputer().isEarlyExit(executable.getExpression())) {
+ needReturn = getExpectedType(executable.getExpression());
+ }
+ it.openScope();
+ generate(executable.getExpression(), needReturn, it, context);
+ it.closeScope();
+ } else if (isAbstract) {
+ it.append("raise Exception(\"Unimplemented function\")"); //$NON-NLS-1$
+ } else {
+ it.append("pass"); //$NON-NLS-1$
+ }
+ it.decreaseIndentation().newLine();
+ //
+ // Generate the additional functions
+ final IActionPrototypeProvider prototypeProvider = getActionPrototypeProvider();
+ final QualifiedActionName actionName = prototypeProvider.createQualifiedActionName(
+ (JvmIdentifiableElement) getJvmModelAssociations().getPrimaryJvmElement(executable.getDeclaringType()),
+ name);
+ final InferredPrototype inferredPrototype = getActionPrototypeProvider().createPrototypeFromSarlModel(actionName,
+ Utils.isVarArg(executable.getParameters()), executable.getParameters());
+ for (final Entry> types : inferredPrototype.getInferredParameterTypes().entrySet()) {
+ final List argumentsToOriginal = types.getValue();
+ it.append("def ").append(name); //$NON-NLS-1$
+ it.append("(self"); //$NON-NLS-1$
+ for (final InferredStandardParameter parameter : argumentsToOriginal) {
+ if (!(parameter instanceof InferredValuedParameter)) {
+ it.append(", "); //$NON-NLS-1$
+ if (((XtendParameter) parameter.getParameter()).isVarArg()) {
+ it.append("*"); //$NON-NLS-1$
+ }
+ it.append(parameter.getName());
+ }
+ }
+ it.append("):"); //$NON-NLS-1$
+ it.increaseIndentation().newLine();
+ if (returnType != null && !"void".equals(returnType.getIdentifier())) { //$NON-NLS-1$
+ it.append("return "); //$NON-NLS-1$
+ }
+ it.append("self.").append(name).append("("); //$NON-NLS-1$ //$NON-NLS-2$
+ boolean first = true;
+ for (final InferredStandardParameter parameter : argumentsToOriginal) {
+ if (first) {
+ first = false;
+ } else {
+ it.append(", "); //$NON-NLS-1$
+ }
+ if (parameter instanceof InferredValuedParameter) {
+ final InferredValuedParameter valuedParameter = (InferredValuedParameter) parameter;
+ generate(((SarlFormalParameter) valuedParameter.getParameter()).getDefaultValue(), null, it, context);
+ } else {
+ it.append(parameter.getName());
+ }
+ }
+ it.append(")"); //$NON-NLS-1$
+ it.decreaseIndentation().newLine();
+ }
+ }
+
+ /** Generate the memorized guard evaluators.
+ *
+ * @param it the output.
+ * @param context the generation context.
+ */
+ @SuppressWarnings({ "unchecked" })
+ protected void generateGuardEvaluators(PyAppendable it, IExtraLanguageGeneratorContext context) {
+ final Map>> guardEvaluators = context.getData(EVENT_GUARDS_MEMENTO, Map.class);
+ if (guardEvaluators == null) {
+ return;
+ }
+ boolean first = true;
+ for (final Entry>> entry : guardEvaluators.entrySet()) {
+ if (first) {
+ first = false;
+ } else {
+ it.newLine();
+ }
+ it.append("def __guard_"); //$NON-NLS-1$
+ it.append(entry.getKey().replaceAll("[^a-zA-Z0-9_]+", "_")); //$NON-NLS-1$ //$NON-NLS-2$
+ it.append("__(self, occurrence):"); //$NON-NLS-1$
+ it.increaseIndentation().newLine();
+ it.append("it = occurrence").newLine(); //$NON-NLS-1$
+ final String eventHandleName = it.declareUniqueNameVariable(new Object(), "__event_handles"); //$NON-NLS-1$
+ it.append(eventHandleName).append(" = list"); //$NON-NLS-1$
+ for (final Pair guardDesc : entry.getValue()) {
+ it.newLine();
+ if (guardDesc.getKey() == null) {
+ it.append(eventHandleName).append(".add(").append(guardDesc.getValue()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
+ } else {
+ it.append("if "); //$NON-NLS-1$
+ generate(guardDesc.getKey(), null, it, context);
+ it.append(":").increaseIndentation().newLine(); //$NON-NLS-1$
+ it.append(eventHandleName).append(".add(").append(guardDesc.getValue()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
+ it.decreaseIndentation();
+ }
+ }
+ it.newLine().append("return ").append(eventHandleName); //$NON-NLS-1$
+ it.decreaseIndentation().newLine();
+ }
+ }
+
+ //----------------------------------------
+ // File Header
+ //----------------------------------------
+
+ @Override
+ protected void generateFileHeader(QualifiedName qualifiedName, ExtraLanguageAppendable appendable,
+ IExtraLanguageGeneratorContext context) {
+ appendable.append(PYTHON_FILE_HEADER);
+ appendable.newLine();
+ appendable.append(getGenerationComment(context));
+ appendable.newLine().newLine();
+ }
+
+ @Override
+ protected void generateImportStatement(QualifiedName qualifiedName, ExtraLanguageAppendable appendable,
+ IExtraLanguageGeneratorContext context) {
+ final String typeName = qualifiedName.getLastSegment();
+ final QualifiedName packageName = qualifiedName.skipLast(1);
+ appendable.append("from "); //$NON-NLS-1$
+ appendable.append(packageName.toString());
+ appendable.append(" import "); //$NON-NLS-1$
+ appendable.append(typeName);
+ appendable.newLine();
+ }
+
+ //----------------------------------------
+ // Types
+ //----------------------------------------
+
+ /** Generate the given object.
+ *
+ * @param clazz the class.
+ * @param context the context.
+ */
+ protected void _generate(SarlClass clazz, IExtraLanguageGeneratorContext context) {
+ final PyAppendable appendable = createAppendable(context);
+ if (generateTypeDeclaration(clazz.getName(), clazz.isAbstract(),
+ getSuperTypes(clazz.getExtends(), clazz.getImplements()), true,
+ clazz.getMembers(), appendable, context, null)) {
+ final QualifiedName name = getQualifiedNameProvider().getFullyQualifiedName(clazz);
+ writeFile(name, appendable, context);
+ }
+ }
+
+ /** Generate the given object.
+ *
+ * @param interf the interface.
+ * @param context the context.
+ */
+ protected void _generate(SarlInterface interf, IExtraLanguageGeneratorContext context) {
+ final PyAppendable appendable = createAppendable(context);
+ if (generateTypeDeclaration(interf.getName(), true, interf.getExtends(), true,
+ interf.getMembers(), appendable, context, null)) {
+ final QualifiedName name = getQualifiedNameProvider().getFullyQualifiedName(interf);
+ writeFile(name, appendable, context);
+ }
+ }
+
+ /** Generate the given object.
+ *
+ * @param enumeration the enumeration.
+ * @param context the context.
+ */
+ protected void _generate(SarlEnumeration enumeration, IExtraLanguageGeneratorContext context) {
+ if (!Strings.isEmpty(enumeration.getName())) {
+ final PyAppendable appendable = createAppendable(context);
+ //
+ appendable.append("class ").append(enumeration.getName()); //$NON-NLS-1$
+ appendable.append("(Enum"); //$NON-NLS-1$
+ appendable.append(newType("enum.Enum")); //$NON-NLS-1$
+ appendable.append("):"); //$NON-NLS-1$
+ appendable.increaseIndentation().newLine();
+ //
+ int i = 0;
+ for (final XtendMember item : enumeration.getMembers()) {
+ if (context.getCancelIndicator().isCanceled()) {
+ return;
+ }
+ if (item instanceof XtendEnumLiteral) {
+ final XtendEnumLiteral literal = (XtendEnumLiteral) item;
+ appendable.append(literal.getName()).append(" = "); //$NON-NLS-1$
+ appendable.append(Integer.toString(i));
+ appendable.newLine();
+ ++i;
+ }
+ }
+ //
+ appendable.decreaseIndentation().newLine().newLine();
+ //
+ final QualifiedName name = getQualifiedNameProvider().getFullyQualifiedName(enumeration);
+ writeFile(name, appendable, context);
+ }
+ }
+
+ /** Generate the given object.
+ *
+ * @param annotation the annotation.
+ * @param context the context.
+ */
+ protected void _generate(SarlAnnotationType annotation, IExtraLanguageGeneratorContext context) {
+ final PyAppendable appendable = createAppendable(context);
+ if (generateTypeDeclaration(annotation.getName(), false, Collections.emptyList(), true,
+ annotation.getMembers(), appendable, context, null)) {
+ final QualifiedName name = getQualifiedNameProvider().getFullyQualifiedName(annotation);
+ writeFile(name, appendable, context);
+ }
+ }
+
+ /** Generate the given object.
+ *
+ * @param event the event.
+ * @param context the context.
+ */
+ protected void _generate(SarlEvent event, IExtraLanguageGeneratorContext context) {
+ final PyAppendable appendable = createAppendable(context);
+ final List superTypes;
+ if (event.getExtends() != null) {
+ superTypes = Collections.singletonList(event.getExtends());
+ } else {
+ superTypes = Collections.singletonList(getTypeReferences().getTypeForName(Event.class, event));
+ }
+ if (generateTypeDeclaration(event.getName(), event.isAbstract(), superTypes, true,
+ event.getMembers(), appendable, context, null)) {
+ final QualifiedName name = getQualifiedNameProvider().getFullyQualifiedName(event);
+ writeFile(name, appendable, context);
+ }
+ }
+
+ /** Generate the given object.
+ *
+ * @param agent the agent.
+ * @param context the context.
+ */
+ protected void _generate(SarlAgent agent, IExtraLanguageGeneratorContext context) {
+ final PyAppendable appendable = createAppendable(context);
+ final List superTypes;
+ if (agent.getExtends() != null) {
+ superTypes = Collections.singletonList(agent.getExtends());
+ } else {
+ superTypes = Collections.singletonList(getTypeReferences().getTypeForName(Agent.class, agent));
+ }
+ if (generateTypeDeclaration(agent.getName(), agent.isAbstract(), superTypes, true,
+ agent.getMembers(), appendable, context, (it, context2) -> {
+ generateGuardEvaluators(it, context2);
+ })) {
+ final QualifiedName name = getQualifiedNameProvider().getFullyQualifiedName(agent);
+ writeFile(name, appendable, context);
+ }
+ }
+
+ /** Generate the given object.
+ *
+ * @param behavior the behavior.
+ * @param context the context.
+ */
+ protected void _generate(SarlBehavior behavior, IExtraLanguageGeneratorContext context) {
+ final PyAppendable appendable = createAppendable(context);
+ final List superTypes;
+ if (behavior.getExtends() != null) {
+ superTypes = Collections.singletonList(behavior.getExtends());
+ } else {
+ superTypes = Collections.singletonList(getTypeReferences().getTypeForName(Behavior.class, behavior));
+ }
+ if (generateTypeDeclaration(behavior.getName(), behavior.isAbstract(), superTypes, true,
+ behavior.getMembers(), appendable, context, (it, context2) -> {
+ generateGuardEvaluators(it, context2);
+ })) {
+ final QualifiedName name = getQualifiedNameProvider().getFullyQualifiedName(behavior);
+ writeFile(name, appendable, context);
+ }
+ }
+
+ /** Generate the given object.
+ *
+ * @param capacity the capacity.
+ * @param context the context.
+ */
+ protected void _generate(SarlCapacity capacity, IExtraLanguageGeneratorContext context) {
+ final PyAppendable appendable = createAppendable(context);
+ final List extends JvmTypeReference> superTypes;
+ if (!capacity.getExtends().isEmpty()) {
+ superTypes = capacity.getExtends();
+ } else {
+ superTypes = Collections.singletonList(getTypeReferences().getTypeForName(Capacity.class, capacity));
+ }
+ if (generateTypeDeclaration(capacity.getName(), true, superTypes, true,
+ capacity.getMembers(), appendable, context, null)) {
+ final QualifiedName name = getQualifiedNameProvider().getFullyQualifiedName(capacity);
+ writeFile(name, appendable, context);
+ }
+ }
+
+ /** Generate the given object.
+ *
+ * @param skill the skill.
+ * @param context the context.
+ */
+ protected void _generate(SarlSkill skill, IExtraLanguageGeneratorContext context) {
+ final PyAppendable appendable = createAppendable(context);
+
+ List superTypes = getSuperTypes(skill.getExtends(), skill.getImplements());
+ if (superTypes.isEmpty()) {
+ superTypes = Collections.singletonList(getTypeReferences().getTypeForName(Skill.class, skill));
+ }
+ if (generateTypeDeclaration(skill.getName(), skill.isAbstract(), superTypes, true,
+ skill.getMembers(), appendable, context, (it, context2) -> {
+ generateGuardEvaluators(it, context2);
+ })) {
+ final QualifiedName name = getQualifiedNameProvider().getFullyQualifiedName(skill);
+ writeFile(name, appendable, context);
+ }
+ }
+
+ //----------------------------------------
+ // Members
+ //----------------------------------------
+
+ /** Generate the given object.
+ *
+ * @param field the fields.
+ * @param it the target for the generated content.
+ * @param context the context.
+ */
+ protected void _generate(SarlField field, PyAppendable it, IExtraLanguageGeneratorContext context) {
+ if (field.isStatic()) {
+ // Static field
+ generatePythonField(field, it, context);
+ } else {
+ final List list = context.getListData(INSTANCE_VARIABLE_MEMENTO, SarlField.class);
+ list.add(field);
+ }
+ }
+
+ /** Generate the given object.
+ *
+ * @param action the action.
+ * @param it the target for the generated content.
+ * @param context the context.
+ */
+ protected void _generate(SarlAction action, PyAppendable it, IExtraLanguageGeneratorContext context) {
+ final String feature = getFeatureNameConverter(context).convertDeclarationName(action.getName(), action);
+ generateExecutable(feature, action, action.isAbstract(),
+ action.getReturnType(), it, context);
+ }
+
+ /** Generate the given object.
+ *
+ * @param constructor the constructor.
+ * @param it the target for the generated content.
+ * @param context the context.
+ */
+ protected void _generate(SarlConstructor constructor, PyAppendable it, IExtraLanguageGeneratorContext context) {
+ generateExecutable("__init__", constructor, false, null, it, context); //$NON-NLS-1$
+ }
+
+ /** Generate the given object.
+ *
+ * @param handler the behavior unit.
+ * @param it the target for the generated content.
+ * @param context the context.
+ */
+ @SuppressWarnings("unchecked")
+ protected void _generate(SarlBehaviorUnit handler, PyAppendable it, IExtraLanguageGeneratorContext context) {
+ final JvmTypeReference event = handler.getName();
+ final String handleName = it.declareUniqueNameVariable(handler, "on_" + event.getSimpleName()); //$NON-NLS-1$
+ it.append("def ").append(handleName).append("(self, occurrence):"); //$NON-NLS-1$ //$NON-NLS-2$
+ it.increaseIndentation().newLine();
+ if (handler.getExpression() != null) {
+ generate(handler.getExpression(), null, it, context);
+ } else {
+ it.append("pass"); //$NON-NLS-1$
+ }
+ it.decreaseIndentation().newLine();
+ Map>> guardEvaluator = context.getData(EVENT_GUARDS_MEMENTO, Map.class);
+ if (guardEvaluator == null) {
+ guardEvaluator = new TreeMap<>();
+ context.setData(EVENT_GUARDS_MEMENTO, guardEvaluator);
+ }
+ List> guards = guardEvaluator.get(event.getQualifiedName());
+ if (guards == null) {
+ guards = new ArrayList<>();
+ guardEvaluator.put(event.getQualifiedName(), guards);
+ }
+ guards.add(new Pair<>(handler.getGuard(), handleName));
+ }
+
+ /** Generate the given object.
+ *
+ * @param uses the capacity uses.
+ * @param it the target for the generated content.
+ * @param context the context.
+ */
+ @SuppressWarnings("static-method")
+ protected void _generate(SarlCapacityUses uses, PyAppendable it, IExtraLanguageGeneratorContext context) {
+ // Rename the function in order to produce the good fetures at the calls.
+ final ImportManager importManager = it.getImportManager();
+ for (final JvmTypeReference capacity : uses.getCapacities()) {
+ final JvmType type = capacity.getType();
+ importManager.addImportFor(type);
+ if (type instanceof JvmDeclaredType) {
+ markCapacitiesFunctions((JvmDeclaredType) type, it);
+ }
+ }
+ }
+
+ private static void markCapacitiesFunctions(JvmDeclaredType leafType, PyAppendable it) {
+ final LinkedList buffer = new LinkedList<>();
+ final Set processed = new TreeSet<>();
+ buffer.addLast(leafType);
+ while (!buffer.isEmpty()) {
+ final JvmDeclaredType type = buffer.removeFirst();
+ boolean markOne = false;
+ for (final JvmOperation operation : type.getDeclaredOperations()) {
+ if (!it.hasName(operation)) {
+ markOne = true;
+ it.declareVariable(operation, "getSkill(" + type.getSimpleName() //$NON-NLS-1$
+ + ")." + operation.getSimpleName()); //$NON-NLS-1$
+ }
+ }
+ if (markOne) {
+ for (final JvmTypeReference superTypeReference : type.getExtendedInterfaces()) {
+ if (processed.add(superTypeReference.getIdentifier())
+ && superTypeReference.getType() instanceof JvmDeclaredType) {
+ buffer.addLast((JvmDeclaredType) superTypeReference.getType());
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/PyGeneratorProvider.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/PyGeneratorProvider.java
new file mode 100644
index 0000000000..4aa8d6da0d
--- /dev/null
+++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/PyGeneratorProvider.java
@@ -0,0 +1,65 @@
+/*
+ * $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.pythongenerator.generator;
+
+import java.util.Collections;
+
+import javax.inject.Inject;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.xtext.generator.IGenerator2;
+import org.eclipse.xtext.generator.IGeneratorContext;
+
+import io.sarl.lang.generator.extra.IExtraLanguageGeneratorProvider;
+import io.sarl.lang.ui.generator.extra.ProjectAdapter;
+import io.sarl.lang.ui.generator.extra.preferences.ExtraLanguagePreferenceAccess;
+import io.sarl.pythongenerator.PyGeneratorPlugin;
+
+/** Provider the Python generator if is it enabled.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public class PyGeneratorProvider implements IExtraLanguageGeneratorProvider {
+
+ @Inject
+ private PyGenerator generator;
+
+ @Inject
+ private ExtraLanguagePreferenceAccess preferences;
+
+ @Override
+ public Iterable getGenerators(IGeneratorContext context, Resource resource) {
+ final IProject project = ProjectAdapter.getProject(resource);
+ if (this.preferences.isGeneratorEnabled(
+ PyGeneratorPlugin.PLUGIN_ID,
+ project)) {
+ return Collections.singletonList(this.generator);
+ }
+ return Collections.emptyList();
+ }
+
+}
diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/PyInitializers.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/PyInitializers.java
new file mode 100644
index 0000000000..d4f70541b3
--- /dev/null
+++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/PyInitializers.java
@@ -0,0 +1,166 @@
+/*
+ * $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.pythongenerator.generator;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.xtext.xbase.lib.Pair;
+
+import io.sarl.lang.generator.extra.IExtraLanguageConversionInitializer;
+import io.sarl.pythongenerator.PyGeneratorPlugin;
+
+/** Initializers for Python 3.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+@SuppressWarnings("checkstyle:classfanoutcomplexity")
+public final class PyInitializers {
+
+ private static final String FEATURE_NAME_PATTERN = "^.*\\.([a-zA-Z_$*]+)(?:\\(.*?\\))?$"; //$NON-NLS-1$
+
+ private static final Pattern FEATURE_NAME_PAT = Pattern.compile(FEATURE_NAME_PATTERN);
+
+ private static final String TYPE_NAME_PATTERN = "^.*[.$]([^.$]+)$"; //$NON-NLS-1$
+
+ private static final Pattern TYPE_NAME_PAT = Pattern.compile(TYPE_NAME_PATTERN);
+
+ private static final String TYPE_CONVERSION_FILENAME = "conversions/type_conversion.properties"; //$NON-NLS-1$
+
+ private static final String FEATURE_CONVERSION_FILENAME = "conversions/feature_name_conversion.properties"; //$NON-NLS-1$
+
+ private PyInitializers() {
+ //
+ }
+
+ private static List> loadPropertyFile(String filename) {
+ final URL url = FileLocator.find(
+ PyGeneratorPlugin.getDefault().getBundle(),
+ Path.fromPortableString(filename),
+ null);
+ final OrderedProperties properties = new OrderedProperties();
+ try (InputStream is = url.openStream()) {
+ properties.load(is);
+ } catch (IOException exception) {
+ PyGeneratorPlugin.getDefault().getLog().log(
+ PyGeneratorPlugin.getDefault().createStatus(IStatus.ERROR, exception));
+ }
+ return properties.getOrderedProperties();
+ }
+
+ /** Replies the initializer for the type converter.
+ *
+ * @return the initializer.
+ */
+ public static IExtraLanguageConversionInitializer getTypeConverterInitializer() {
+ return (it) -> {
+ final List> properties = loadPropertyFile(TYPE_CONVERSION_FILENAME);
+ if (!properties.isEmpty()) {
+ for (final Pair entry : properties) {
+ final String source = Objects.toString(entry.getKey());
+ final String target = Objects.toString(entry.getValue());
+ final String baseName;
+ final Matcher matcher = TYPE_NAME_PAT.matcher(source);
+ if (matcher.find()) {
+ baseName = matcher.group(1);
+ } else {
+ baseName = source;
+ }
+ it.apply(baseName, source, target);
+ }
+ }
+ };
+ }
+
+ /** Replies the initializer for the feature name converter.
+ *
+ * @return the initializer.
+ */
+ public static IExtraLanguageConversionInitializer getFeatureNameConverterInitializer() {
+ return (it) -> {
+ final List> properties = loadPropertyFile(FEATURE_CONVERSION_FILENAME);
+ if (!properties.isEmpty()) {
+ for (final Pair entry : properties) {
+ final String source = Objects.toString(entry.getKey());
+ final String target = Objects.toString(entry.getValue());
+ final Matcher matcher = FEATURE_NAME_PAT.matcher(source);
+ final String featureName;
+ if (matcher.find()) {
+ featureName = matcher.group(1);
+ } else {
+ featureName = source;
+ }
+ it.apply(featureName, source, target);
+ }
+ }
+ };
+ }
+
+ /** Specific properties with reading order.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+ private static class OrderedProperties extends Properties {
+
+ private static final long serialVersionUID = 162949168401947298L;
+
+ private final List> orderedElements = new ArrayList<>();
+
+ OrderedProperties() {
+ //
+ }
+
+ @Override
+ public synchronized Object put(Object key, Object value) {
+ this.orderedElements.add(new Pair<>(Objects.toString(key), Objects.toString(value)));
+ return super.put(key, value);
+ }
+
+ /** Replies the ordered elements.
+ *
+ * @return the ordered elements.
+ */
+ public List> getOrderedProperties() {
+ return this.orderedElements;
+ }
+
+ }
+
+}
diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/messages.properties b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/messages.properties
new file mode 100644
index 0000000000..15f46be0b8
--- /dev/null
+++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/messages.properties
@@ -0,0 +1,3 @@
+PyOutputConfigurationProvider_0=Python 3 Output Configuration
+PyExpressionGenerator_0=Unsupported operator to Python: {0}
+
diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/ui/GeneratorConfigurationBlock.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/ui/GeneratorConfigurationBlock.java
new file mode 100644
index 0000000000..283faddf5d
--- /dev/null
+++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/ui/GeneratorConfigurationBlock.java
@@ -0,0 +1,68 @@
+/*
+ * $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.pythongenerator.ui;
+
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.swt.graphics.Image;
+
+import io.sarl.lang.ui.generator.extra.properties.AbstractGeneratorConfigurationBlock;
+import io.sarl.pythongenerator.PyGeneratorPlugin;
+
+/** Configuration block for the Python generator.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public class GeneratorConfigurationBlock extends AbstractGeneratorConfigurationBlock {
+
+ private static final String PYTHON_ICON = "icons/python.png"; //$NON-NLS-1$
+
+ /** Constructor.
+ */
+ public GeneratorConfigurationBlock() {
+ super(true);
+ }
+
+ @Override
+ public IDialogSettings getDialogSettings() {
+ return PyGeneratorPlugin.getDefault().getDialogSettings();
+ }
+
+ @Override
+ public String getPluginID() {
+ return PyGeneratorPlugin.PLUGIN_ID;
+ }
+
+ @Override
+ protected String getActivationText() {
+ return Messages.GeneratorConfigurationBlock_5;
+ }
+
+ @Override
+ public Image getTargetLanguageImage() {
+ return PyGeneratorPlugin.getDefault().getImage(PYTHON_ICON);
+ }
+
+}
diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/ui/Messages.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/ui/Messages.java
new file mode 100644
index 0000000000..8b2a6eecd1
--- /dev/null
+++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/ui/Messages.java
@@ -0,0 +1,44 @@
+/*
+ * $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.pythongenerator.ui;
+
+import org.eclipse.osgi.util.NLS;
+
+/** Messages.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+@SuppressWarnings("all")
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
+ public static String GeneratorConfigurationBlock_5;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/ui/PropertyPage.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/ui/PropertyPage.java
new file mode 100644
index 0000000000..954e7118e1
--- /dev/null
+++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/ui/PropertyPage.java
@@ -0,0 +1,53 @@
+/*
+ * $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.pythongenerator.ui;
+
+import com.google.inject.Inject;
+
+import io.sarl.lang.ui.generator.extra.properties.AbstractExtraLanguagePropertyPage;
+import io.sarl.pythongenerator.PyGeneratorPlugin;
+
+/** Property page for configuring the Python generator.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public class PropertyPage extends AbstractExtraLanguagePropertyPage {
+
+ /** Inject the configuration block.
+ *
+ * @param block the block.
+ */
+ @Inject
+ public void setGeneratorConfigurationBlock(GeneratorConfigurationBlock block) {
+ setInternalConfigurationBlock(block);
+ }
+
+ @Override
+ protected String getGeneratorPageID() {
+ return PyGeneratorPlugin.PLUGIN_ID;
+ }
+
+}
diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/ui/messages.properties b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/ui/messages.properties
new file mode 100644
index 0000000000..34ae0be967
--- /dev/null
+++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/ui/messages.properties
@@ -0,0 +1 @@
+GeneratorConfigurationBlock_5=Python generator is activated
diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/validator/Messages.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/validator/Messages.java
new file mode 100644
index 0000000000..c3e3e81485
--- /dev/null
+++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/validator/Messages.java
@@ -0,0 +1,53 @@
+/*
+ * $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.pythongenerator.validator;
+
+import org.eclipse.osgi.util.NLS;
+
+/** Localized Messages.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+@SuppressWarnings("all")
+public final class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages";
+
+ public static String PyValidator_0;
+
+ public static String PyValidator_1;
+
+ public static String PyValidator_2;
+
+ public static String PyValidator_3;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/validator/PyValidator.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/validator/PyValidator.java
new file mode 100644
index 0000000000..73397fd8d0
--- /dev/null
+++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/validator/PyValidator.java
@@ -0,0 +1,124 @@
+/*
+ * $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.pythongenerator.validator;
+
+import java.text.MessageFormat;
+
+import javax.inject.Inject;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.common.types.JvmConstructor;
+import org.eclipse.xtext.common.types.JvmDeclaredType;
+import org.eclipse.xtext.common.types.JvmField;
+import org.eclipse.xtext.common.types.JvmIdentifiableElement;
+import org.eclipse.xtext.common.types.JvmOperation;
+import org.eclipse.xtext.common.types.JvmType;
+import org.eclipse.xtext.validation.Check;
+import org.eclipse.xtext.xbase.XFeatureCall;
+import org.eclipse.xtext.xbase.XMemberFeatureCall;
+import org.eclipse.xtext.xbase.featurecalls.IdentifiableSimpleNameProvider;
+import org.eclipse.xtext.xbase.lib.Functions.Function2;
+import org.eclipse.xtext.xbase.lib.Procedures.Procedure3;
+import org.eclipse.xtext.xtype.XImportDeclaration;
+
+import io.sarl.lang.generator.extra.IExtraLanguageConversionInitializer;
+import io.sarl.lang.validation.extra.AbstractExtraLanguageValidator;
+import io.sarl.pythongenerator.PyGeneratorPlugin;
+import io.sarl.pythongenerator.generator.PyInitializers;
+
+/** The validator from SARL to the Python target language.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public class PyValidator extends AbstractExtraLanguageValidator {
+
+ private final Procedure3 typeErrorHandler = (source, invalidType, name) -> {
+ error(MessageFormat.format(Messages.PyValidator_0, name), source);
+ };
+
+ private final Function2 featureErrorHandlerr = (source, element) -> {
+ final String message;
+ if (element instanceof JvmConstructor) {
+ message = MessageFormat.format(Messages.PyValidator_1, this.simpleNameProvider.getSimpleName(element));
+ } else if (element instanceof JvmField) {
+ message = MessageFormat.format(Messages.PyValidator_2, this.simpleNameProvider.getSimpleName(element));
+ } else if (element instanceof JvmOperation) {
+ message = MessageFormat.format(Messages.PyValidator_3, this.simpleNameProvider.getSimpleName(element));
+ } else {
+ // This type of Jvm element is not supposed to be converted
+ return false;
+ }
+ error(message, source);
+ return true;
+ };
+
+ @Inject
+ private IdentifiableSimpleNameProvider simpleNameProvider;
+
+ @Override
+ protected IExtraLanguageConversionInitializer getTypeConverterInitializer() {
+ return PyInitializers.getTypeConverterInitializer();
+ }
+
+ @Override
+ protected IExtraLanguageConversionInitializer getFeatureConverterInitializer() {
+ return PyInitializers.getFeatureNameConverterInitializer();
+ }
+
+ @Override
+ protected String getGeneratorPluginID() {
+ return PyGeneratorPlugin.PLUGIN_ID;
+ }
+
+ /** Check that import mapping are known.
+ *
+ * @param importDeclaration the declaration.
+ */
+ @Check
+ public void checkImportsMapping(XImportDeclaration importDeclaration) {
+ final JvmDeclaredType type = importDeclaration.getImportedType();
+ doTypeMappingCheck(importDeclaration, type, this.typeErrorHandler);
+ }
+
+ /** Check that member feature calls have a convertion mapping.
+ *
+ * @param featureCall the feature call.
+ */
+ @Check
+ public void checkMemberFeatureCallMapping(XMemberFeatureCall featureCall) {
+ doCheckMemberFeatureCallMapping(featureCall, this.typeErrorHandler, this.featureErrorHandlerr);
+ }
+
+ /** Check that member feature calls have a convertion mapping.
+ *
+ * @param featureCall the feature call.
+ */
+ @Check
+ public void checkMemberFeatureCallMapping(XFeatureCall featureCall) {
+ doCheckMemberFeatureCallMapping(featureCall, this.typeErrorHandler, this.featureErrorHandlerr);
+ }
+
+}
diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/validator/PyValidatorProvider.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/validator/PyValidatorProvider.java
new file mode 100644
index 0000000000..64e1c49699
--- /dev/null
+++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/validator/PyValidatorProvider.java
@@ -0,0 +1,64 @@
+/*
+ * $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.pythongenerator.validator;
+
+import java.util.Collections;
+
+import javax.inject.Inject;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.emf.ecore.EValidator;
+import org.eclipse.emf.ecore.resource.Resource;
+
+import io.sarl.lang.ui.generator.extra.ProjectAdapter;
+import io.sarl.lang.ui.generator.extra.preferences.ExtraLanguagePreferenceAccess;
+import io.sarl.lang.validation.extra.IExtraLanguageValidatorProvider;
+import io.sarl.pythongenerator.PyGeneratorPlugin;
+
+/** Provider the Python validator if is it enabled.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public class PyValidatorProvider implements IExtraLanguageValidatorProvider {
+
+ @Inject
+ private PyValidator validator;
+
+ @Inject
+ private ExtraLanguagePreferenceAccess preferences;
+
+ @Override
+ public Iterable getValidators(Resource resource) {
+ final IProject project = ProjectAdapter.getProject(resource);
+ if (this.preferences.isGeneratorEnabled(
+ PyGeneratorPlugin.PLUGIN_ID,
+ project)) {
+ return Collections.singletonList(this.validator);
+ }
+ return Collections.emptyList();
+ }
+
+}
diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/validator/messages.properties b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/validator/messages.properties
new file mode 100644
index 0000000000..a35865371a
--- /dev/null
+++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/validator/messages.properties
@@ -0,0 +1,4 @@
+PyValidator_0=No Python translation to the type {0}.
+PyValidator_1=No Python translation to the constructor call of {0}.
+PyValidator_2=No Python translation to the field {0}.
+PyValidator_3=No Python translation to the method {0}.
diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.tests/pom.xml b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.tests/pom.xml
new file mode 100644
index 0000000000..0691a902c0
--- /dev/null
+++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.tests/pom.xml
@@ -0,0 +1,27 @@
+
+ 4.0.0
+
+ io.sarl.pythongenerator
+ io.sarl.pythongenerator
+ 0.6.0-SNAPSHOT
+
+
+ io.sarl.pythongenerator.tests
+ Python Generator Tests
+
+
+
+ io.sarl
+ io.sarl.tests.api
+ test
+
+
+ io.sarl.pythongenerator
+ io.sarl.pythongenerator.plugin
+ ${sarl.version}
+ test
+
+
+
+
diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.tests/src/test/java/io/sarl/pythongenerator/tests/PyGeneratorTest.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.tests/src/test/java/io/sarl/pythongenerator/tests/PyGeneratorTest.java
new file mode 100644
index 0000000000..e96276b21b
--- /dev/null
+++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.tests/src/test/java/io/sarl/pythongenerator/tests/PyGeneratorTest.java
@@ -0,0 +1,734 @@
+/*
+ * $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.pythongenerator.tests;
+
+import org.junit.Test;
+
+import io.sarl.pythongenerator.configuration.PyOutputConfigurationProvider;
+import io.sarl.pythongenerator.generator.PyGenerator;
+import io.sarl.tests.api.AbstractExtraLanguageGeneratorTest;
+import io.sarl.tests.api.AbstractExtraLanguageGeneratorTest.GeneratorTest;
+
+
+/**
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+@SuppressWarnings("all")
+public class PyGeneratorTest extends AbstractExtraLanguageGeneratorTest {
+
+ @Override
+ protected String getOutputConfigurationName() {
+ return PyOutputConfigurationProvider.OUTPUT_CONFIGURATION_NAME;
+ }
+
+ @Test
+ public void basic() throws Exception {
+ String source = "class C1 { }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void variable() throws Exception {
+ String source = "class C1 { var v = 45 }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef __init__(self):",
+ "\t\tself.v = 45");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void value() throws Exception {
+ String source = "class C1 { val v = 45 }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef __init__(self):",
+ "\t\tself.v = 45");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void method_0() throws Exception {
+ String source = "class C1 { def fct { 4 } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self):",
+ "\t\t4",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void method_1() throws Exception {
+ String source = "class C1 { def fct(a : int) { a } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, a):",
+ "\t\ta",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void method_2() throws Exception {
+ String source = "class C1 { def fct(a : int*) { 5 } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, *a):",
+ "\t\t5",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void method_3() throws Exception {
+ String source = "class C1 { def fct(a : int = 6) { 5 } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, a):",
+ "\t\t5",
+ "\tdef fct(self):",
+ "\t\tself.fct(6)",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void method_4() throws Exception {
+ String source = "class C1 { def fct : int { 4 } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self):",
+ "\t\treturn 4",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void method_5() throws Exception {
+ String source = "class C1 { def fct(a : int) : int { a } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, a):",
+ "\t\treturn a",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void method_6() throws Exception {
+ String source = "class C1 { def fct(a : int*) : int { 5 } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, *a):",
+ "\t\treturn 5",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void method_7() throws Exception {
+ String source = "class C1 { def fct(a : int = 6) : int { 5 } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, a):",
+ "\t\treturn 5",
+ "\tdef fct(self):",
+ "\t\treturn self.fct(6)",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void methodOverriding_explicitReturnType() throws Exception {
+ String source = multilineString(
+ "package io.sarl.docs.reference.oop",
+ "class Person {",
+ " var firstName : String",
+ " var lastName : String",
+ " def getFullName : String {",
+ " this.firstName + \" \" + this.lastName",
+ " }",
+ "}",
+ "class PersonEx extends Person {",
+ " var title : String",
+ " override getFullName : String {",
+ " return title + \" \" + super.fullName",
+ " }",
+ "}");
+ String expected1 = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class Person(object):",
+ "\tdef getFullName(self):",
+ "\t\treturn self.firstName + u\" \" + self.lastName",
+ "\tdef __init__(self):",
+ "\t\tself.firstName = None",
+ "\t\tself.lastName = None");
+ String expected2 = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "from io.sarl.docs.reference.oop import Person",
+ "",
+ "class PersonEx(Person):",
+ "\tdef getFullName(self):",
+ "\t\treturn self.title + u\" \" + super().getFullName()",
+ "\tdef __init__(self):",
+ "\t\tself.title = None");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("io.sarl.docs.reference.oop.Person", expected1);
+ gen.assertTypeDefinition("io.sarl.docs.reference.oop.PersonEx", expected2);
+ }
+
+ @Test
+ public void methodOverriding_inferredReturnType() throws Exception {
+ String source = multilineString(
+ "package io.sarl.docs.reference.oop",
+ "class Person {",
+ " var firstName : String",
+ " var lastName : String",
+ " def getFullName : String {",
+ " this.firstName + \" \" + this.lastName",
+ " }",
+ "}",
+ "class PersonEx extends Person {",
+ " var title : String",
+ " override getFullName {",
+ " return title + \" \" + super.fullName",
+ " }",
+ "}");
+ String expected1 = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class Person(object):",
+ "\tdef getFullName(self):",
+ "\t\treturn self.firstName + u\" \" + self.lastName",
+ "\tdef __init__(self):",
+ "\t\tself.firstName = None",
+ "\t\tself.lastName = None");
+ String expected2 = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "from io.sarl.docs.reference.oop import Person",
+ "",
+ "class PersonEx(Person):",
+ "\tdef getFullName(self):",
+ "\t\treturn self.title + u\" \" + super().getFullName()",
+ "\tdef __init__(self):",
+ "\t\tself.title = None");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("io.sarl.docs.reference.oop.Person", expected1);
+ gen.assertTypeDefinition("io.sarl.docs.reference.oop.PersonEx", expected2);
+ }
+
+ @Test
+ public void postfixOperator() throws Exception {
+ String source = "class C1 { def fct(a : int) : int { a++; return a } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, a):",
+ "\t\ta += 1",
+ "\t\treturn a",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void incrementOperator() throws Exception {
+ String source = "class C1 { def fct(a : int) : int { a += 5 ; return a } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, a):",
+ "\t\ta += 5",
+ "\t\treturn a",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void unaryOperator() throws Exception {
+ String source = "class C1 { def fct(a : int) : int { a = -a + 6 ; return a } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, a):",
+ "\t\ta = -a + 6",
+ "\t\treturn a",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void whileStatement() throws Exception {
+ String source = "class C1 { def fct(a : int) { while (a > 0) { a-- } } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, a):",
+ "\t\twhile a > 0:",
+ "\t\t\ta -= 1",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void doWhileStatement() throws Exception {
+ String source = "class C1 { def fct(a : int) { do { a-- } while ((a > 0) } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, a):",
+ "\t\ta -= 1",
+ "\t\twhile a > 0:",
+ "\t\t\ta -= 1",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void basicForLoopStatement() throws Exception {
+ String source = "class C1 { def fct(a : int) { for(var i = 0; i < 5; i++ { a-- } } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, a):",
+ "\t\ti = 0",
+ "\t\twhile i < 5:",
+ "\t\t\ta -= 1",
+ "\t\t\ti += 1",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void forLoopStatement() throws Exception {
+ String source = "class C1 { def fct(a : int[]) : int { var s = 0; for(e : a) { s += e }; return s } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, a):",
+ "\t\ts = 0",
+ "\t\tfor e in a:",
+ "\t\t\ts += e",
+ "\t\treturn s",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void ifStatement() throws Exception {
+ String source = "class C1 { def fct(a : int) : int { if (a > 0) a + 5 } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, a):",
+ "\t\tif a > 0:",
+ "\t\t\treturn a + 5",
+ "\t\telse:",
+ "\t\t\treturn 0",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void ifElseStatement() throws Exception {
+ String source = "class C1 { def fct(a : int) : int { if (a > 0) a + 5 else a - 6 } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, a):",
+ "\t\tif a > 0:",
+ "\t\t\treturn a + 5",
+ "\t\telse:",
+ "\t\t\treturn a - 6",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void switchStatement() throws Exception {
+ String source = multilineString(
+ "class C1 {",
+ " def fct(a : Object) : int {",
+ " switch (a) {",
+ " case 1: return 1",
+ " case 32: return 2",
+ " case (a as Integer) > 32: return 3",
+ " String: return 4",
+ " String case \"34\": return 5",
+ " case 2,",
+ " case 3: return 6",
+ " default: return 0",
+ " }",
+ " }",
+ "}");
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, a):",
+ "\t\t___expression = a",
+ "\t\tif ((1) == ___expression):",
+ "\t\t\treturn 1",
+ "\t\telif ((32) == ___expression):",
+ "\t\t\treturn 2",
+ "\t\telif ((a > 32)):",
+ "\t\t\treturn 3",
+ "\t\telif (isinstance(___expression, unicode)):",
+ "\t\t\treturn 4",
+ "\t\telif (isinstance(___expression, unicode) and (u\"34\") == ___expression):",
+ "\t\t\treturn 5",
+ "\t\telif ((2) == ___expression) or ((3) == ___expression):",
+ "\t\t\treturn 6",
+ "\t\telse:",
+ "\t\t\treturn 0",
+ "\t\t",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void tryCatchStatement() throws Exception {
+ String source = multilineString(
+ "class C1 {",
+ " def fct(a : int) : int {",
+ " try {",
+ " return a + 1",
+ " } catch (e : Exception) {",
+ " return a + 2",
+ " } finally {",
+ " return a + 3",
+ " }",
+ " }",
+ "}");
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, a):",
+ "\t\ttry:",
+ "\t\t\treturn a + 1",
+ "\t\texcept Exception, e:",
+ "\t\t\treturn a + 2",
+ "\t\tfinally:",
+ "\t\t\treturn a + 3",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void constructorCallStatement() throws Exception {
+ String source = multilineString(
+ "class C1 {",
+ " new(a : int) { }",
+ "}",
+ "class C2 {",
+ " def fct : C1 {",
+ " return new C1(5)",
+ " }",
+ "}");
+ String expected1 = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef __init__(self, a):",
+ "\t\tpass");
+ String expected2 = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C2(object):",
+ "\tdef fct(self):",
+ "\t\treturn C1(5)",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected1);
+ gen.assertTypeDefinition("C2", expected2);
+ }
+
+ @Test
+ public void closureStatement() throws Exception {
+ String source = multilineString(
+ "class C1 {",
+ " def fct(f : (int) => float) {",
+ " }",
+ " def fct2 {",
+ " fct [ it + 2.0 ]",
+ " }",
+ "}");
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, f):",
+ "\t\tpass",
+ "\tdef fct2(self):",
+ "\t\tdef __closure(self, it):",
+ "\t\t\treturn it + 2.0",
+ "\t\tself.fct(__closure)",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void anonStatement() throws Exception {
+ String source = multilineString(
+ "interface C1 {",
+ " def fct(a : int) : float",
+ "}",
+ "class C2 {",
+ " def fct(f : C1) {",
+ " }",
+ " def fct2 {",
+ " fct(new C1 {",
+ " def fct(a : int) { 0 }",
+ " })",
+ " }",
+ "}");
+ String expected1 = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef fct(self, a):",
+ "\t\traise Exception(\"Unimplemented function\")",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ String expected2 = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C2(object):",
+ "\tdef fct(self, f):",
+ "\t\tpass",
+ "\tdef fct2(self):",
+ "\t\tclass AnonClass(C1,object):",
+ "\t\t\tdef fct(self, a):",
+ "\t\t\t\t0",
+ "\t\t\tdef __init__(self):",
+ "\t\t\t\tpass",
+ "\t\t\t",
+ "\t\t",
+ "\t\tself.fct(AnonClass)",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected1);
+ gen.assertTypeDefinition("C2", expected2);
+ }
+
+ @Test
+ public void constructor_0() throws Exception {
+ String source = "class C1 { var x : int new { x = 4 } }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef __init__(self):",
+ "\t\tself.x = 4");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void field_0() throws Exception {
+ String source = "class C1 { var x : int }";
+ String expected = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "class C1(object):",
+ "\tdef __init__(self):",
+ "\t\tself.x = 0");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected);
+ }
+
+ @Test
+ public void agent_0() throws Exception {
+ String source = multilineString(
+ "event E1",
+ "agent A1 {",
+ " var attr = 6",
+ " def myfct { }",
+ " on E1 { }",
+ " on E1 [ attr > 0 ] { }",
+ " on E1 [ occurrence.isFromMe ] { }",
+ "}");
+ String expected1 = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "from io.sarl.lang.core import Event",
+ "",
+ "class E1(Event):",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ String expected2 = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "from io.sarl.lang.core import Agent",
+ "",
+ "class A1(Agent):",
+ "\tdef myfct(self):",
+ "\t\tpass",
+ "\tdef on_E1(self, occurrence):",
+ "\t\tpass",
+ "\tdef on_E1_1(self, occurrence):",
+ "\t\tpass",
+ "\tdef on_E1_2(self, occurrence):",
+ "\t\tpass",
+ "\tdef __guard_E1__(self, occurrence):",
+ "\t\tit = occurrence",
+ "\t\t__event_handles = list",
+ "\t\t__event_handles.add(on_E1)",
+ "\t\tif self.attr > 0:",
+ "\t\t\t__event_handles.add(on_E1_1)",
+ "\t\tif self.isFromMe(occurrence):",
+ "\t\t\t__event_handles.add(on_E1_2)",
+ "\t\treturn __event_handles",
+ "\tdef __init__(self):",
+ "\t\tself.attr = 6");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("E1", expected1);
+ gen.assertTypeDefinition("A1", expected2);
+ }
+
+ @Test
+ public void capacityuses_0() throws Exception {
+ String source = multilineString(
+ "capacity C1 {",
+ " def fct1 : int",
+ " def fct2(a : char)",
+ "}",
+ "behavior B1 {",
+ " uses C1",
+ " def myfct {",
+ " var a = fct1 + 1",
+ " }",
+ "}");
+ String expected1 = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "from io.sarl.lang.core import Capacity",
+ "",
+ "class C1(Capacity):",
+ "\tdef fct1(self):",
+ "\t\traise Exception(\"Unimplemented function\")",
+ "\tdef fct2(self, a):",
+ "\t\traise Exception(\"Unimplemented function\")",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ String expected2 = multilineString(
+ PyGenerator.PYTHON_FILE_HEADER,
+ "",
+ "from io.sarl.lang.core import Behavior",
+ "",
+ "class B1(Behavior):",
+ "\tdef myfct(self):",
+ "\t\ta = self.getSkill(C1).fct1() + 1",
+ "\tdef __init__(self):",
+ "\t\tpass");
+ GeneratorTest gen = compile(source);
+ gen.assertTypeDefinition("C1", expected1);
+ gen.assertTypeDefinition("B1", expected2);
+ }
+
+}
diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.tests/src/test/java/io/sarl/pythongenerator/tests/PyValidatorTest.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.tests/src/test/java/io/sarl/pythongenerator/tests/PyValidatorTest.java
new file mode 100644
index 0000000000..a530f018c5
--- /dev/null
+++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.tests/src/test/java/io/sarl/pythongenerator/tests/PyValidatorTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.pythongenerator.tests;
+
+import org.eclipse.xtext.xbase.XbasePackage;
+import org.eclipse.xtext.xbase.validation.IssueCodes;
+import org.eclipse.xtext.xtype.XtypePackage;
+import org.junit.Test;
+
+import io.sarl.lang.sarl.SarlScript;
+import io.sarl.tests.api.AbstractSarlTest;
+
+/**
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+@SuppressWarnings("all")
+public class PyValidatorTest extends AbstractSarlTest {
+
+ @Test
+ public void basic() throws Exception {
+ String source = "class C1 { }";
+ SarlScript mas = file(source);
+ validate(mas).assertNoErrors();
+ }
+
+ @Test
+ public void variable() throws Exception {
+ String source = "class C1 { var v = 45 }";
+ SarlScript mas = file(source);
+ validate(mas).assertNoErrors();
+ }
+
+ @Test
+ public void field_0() throws Exception {
+ String source = "class C1 { var x : int }";
+ SarlScript mas = file(source);
+ validate(mas).assertNoErrors();
+ }
+
+ @Test
+ public void agent_0() throws Exception {
+ String source = multilineString(
+ "event E1",
+ "agent A1 {",
+ " var attr = 6",
+ " def myfct { }",
+ " on E1 { }",
+ " on E1 [ attr > 0 ] { }",
+ " on E1 [ occurrence.isFromMe ] { }",
+ "}");
+ SarlScript mas = file(source);
+ validate(mas).assertNoErrors();
+ }
+
+ @Test
+ public void capacityuses_0() throws Exception {
+ String source = multilineString(
+ "capacity C1 {",
+ " def fct1 : int",
+ " def fct2(a : char)",
+ "}",
+ "behavior B1 {",
+ " uses C1",
+ " def myfct {",
+ " var a = fct1 + 1",
+ " }",
+ "}");
+ SarlScript mas = file(source);
+ validate(mas).assertNoErrors();
+ }
+
+ @Test
+ public void importStatement_0() throws Exception {
+ String source = multilineString(
+ "import java.net.URL",
+ "class C1 {",
+ " def myfct {",
+ " var url : URL",
+ " }",
+ "}");
+ SarlScript mas = file(source);
+ validate(mas).assertError(
+ XtypePackage.eINSTANCE.getXImportDeclaration(),
+ IssueCodes.IMPORT_CONFLICT);
+ }
+
+}
diff --git a/contribs/io.sarl.pythongenerator/pom.xml b/contribs/io.sarl.pythongenerator/pom.xml
new file mode 100644
index 0000000000..cd74262c0f
--- /dev/null
+++ b/contribs/io.sarl.pythongenerator/pom.xml
@@ -0,0 +1,22 @@
+
+ 4.0.0
+
+ io.sarl
+ io.sarl.products.contribs
+ 0.6.0-SNAPSHOT
+
+
+ io.sarl.pythongenerator
+ io.sarl.pythongenerator
+ pom
+
+ Python Generator for SARL Compiler
+
+
+ io.sarl.pythongenerator.plugin
+ io.sarl.pythongenerator.feature
+
+
+
+
diff --git a/contribs/pom.xml b/contribs/pom.xml
index 2dc2cd93cb..978acc3609 100644
--- a/contribs/pom.xml
+++ b/contribs/pom.xml
@@ -15,6 +15,7 @@
Contributions to SARL
+ io.sarl.pythongenerator
io.sarl.examples
io.sarl.experienceindex
diff --git a/main/apiplugins/io.sarl.util/src/io/sarl/eventdispatching/Messages.sarl b/main/apiplugins/io.sarl.util/src/io/sarl/eventdispatching/Messages.sarl
index 2b32caee54..d6083d7d3e 100644
--- a/main/apiplugins/io.sarl.util/src/io/sarl/eventdispatching/Messages.sarl
+++ b/main/apiplugins/io.sarl.util/src/io/sarl/eventdispatching/Messages.sarl
@@ -32,7 +32,7 @@ import org.eclipse.osgi.util.NLS
final class Messages extends NLS {
private static val BUNDLE_NAME = {
- val name = "io.sarl.eventdispatching.messages"
+ val name = typeof(Messages).getPackage.name + ".messages"
// initialize resource bundle
NLS.initializeMessages(name, typeof(Messages))
name
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/buildpath/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/buildpath/Messages.java
index d85f0e5f25..58ebed57b4 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/buildpath/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/buildpath/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.buildpath.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
public static String SARLClasspathContainer_0;
public static String SARLClasspathContainerInitializer_0;
public static String SARLContainerWizardPage_0;
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/launching/dialog/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/launching/dialog/Messages.java
index bd93c8620e..201e33596f 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/launching/dialog/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/launching/dialog/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.launching.dialog.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
public static String MainLaunchConfigurationTab_0;
public static String MainLaunchConfigurationTab_1;
public static String MainLaunchConfigurationTab_10;
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/launching/runner/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/launching/runner/Messages.java
index acaaa4480c..206b515760 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/launching/runner/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/launching/runner/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.launching.runner.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
public static String SARLLaunchConfigurationDelegate_0;
public static String SARLLaunchConfigurationDelegate_1;
public static String SARLLaunchConfigurationDelegate_2;
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/launching/shortcuts/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/launching/shortcuts/Messages.java
index e9830e765f..f2841480d6 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/launching/shortcuts/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/launching/shortcuts/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.launching.shortcuts.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
public static String SARLLaunchShortcut_0;
public static String SARLLaunchShortcut_2;
public static String SARLLaunchShortcut_5;
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/log/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/log/Messages.java
index 49a32d52a2..65c8d6461d 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/log/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/log/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.log.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/natures/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/natures/Messages.java
index 0e376a6d2a..647f7d61f2 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/natures/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/natures/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.natures.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
public static String AddSarlNatureHandler_2;
public static String RemoveSarlNatureHandler_0;
public static String RemoveSarlNatureHandler_1;
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/preferences/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/preferences/Messages.java
index 358fb57fc6..aba60341c1 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/preferences/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/preferences/Messages.java
@@ -31,7 +31,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.preferences.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
public static String SREsPreferencePage_0;
public static String SREsPreferencePage_1;
public static String SREsPreferencePage_10;
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/runtime/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/runtime/Messages.java
index 4dbf1b7053..caec25d041 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/runtime/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/runtime/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.runtime.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
public static String SARLRuntime_0;
public static String SARLRuntime_1;
public static String SARLRuntime_2;
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newagent/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newagent/Messages.java
index e3d46ebbb0..6e31536aca 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newagent/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newagent/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.wizards.elements.aop.newagent.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newbehavior/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newbehavior/Messages.java
index b24e4801eb..412b3f849b 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newbehavior/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newbehavior/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.wizards.elements.aop.newbehavior.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newcapacity/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newcapacity/Messages.java
index 8964eae1f8..d4174e26d0 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newcapacity/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newcapacity/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.wizards.elements.aop.newcapacity.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newevent/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newevent/Messages.java
index f3b71504a9..501d89e8fe 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newevent/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newevent/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.wizards.elements.aop.newevent.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newskill/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newskill/Messages.java
index f3c4357958..2bc17f2040 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newskill/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/aop/newskill/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.wizards.elements.aop.newskill.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/oop/newanno/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/oop/newanno/Messages.java
index 19ede8cc6c..fd5f9816cc 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/oop/newanno/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/oop/newanno/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.wizards.elements.oop.newanno.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/oop/newclass/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/oop/newclass/Messages.java
index bb7c123aec..8d5d339d39 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/oop/newclass/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/oop/newclass/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.wizards.elements.oop.newclass.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/oop/newenum/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/oop/newenum/Messages.java
index 476226c9df..36c8773ce8 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/oop/newenum/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/oop/newenum/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.wizards.elements.oop.newenum.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/oop/newinterface/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/oop/newinterface/Messages.java
index 8ca94b9762..1eac72964d 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/oop/newinterface/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/elements/oop/newinterface/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.wizards.elements.oop.newinterface.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/newfile/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/newfile/Messages.java
index ddfaf3e53f..ad21038716 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/newfile/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/newfile/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.wizards.newfile.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/newproject/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/newproject/Messages.java
index dac5a1937f..c779bec290 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/newproject/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/newproject/Messages.java
@@ -33,7 +33,7 @@
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.wizards.newproject.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
public static String BuildSettingWizardPage_0;
diff --git a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/sreinstall/Messages.java b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/sreinstall/Messages.java
index 27d1e65908..003a7f8090 100644
--- a/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/sreinstall/Messages.java
+++ b/main/coreplugins/io.sarl.eclipse/src/io/sarl/eclipse/wizards/sreinstall/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.eclipse.wizards.sreinstall.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
public static String SREInstallWizard_0;
public static String SREInstallWizard_1;
public static String SREInstallWizard_2;
diff --git a/main/coreplugins/io.sarl.lang.ui/META-INF/MANIFEST.MF b/main/coreplugins/io.sarl.lang.ui/META-INF/MANIFEST.MF
index ad1ab6cc7c..1b43de59af 100644
--- a/main/coreplugins/io.sarl.lang.ui/META-INF/MANIFEST.MF
+++ b/main/coreplugins/io.sarl.lang.ui/META-INF/MANIFEST.MF
@@ -21,13 +21,15 @@ Require-Bundle: io.sarl.lang;bundle-version="0.6.0";visibility:=reexport,
org.eclipse.jdt.debug.ui;bundle-version="3.7.201",
org.eclipse.ui;bundle-version="3.108.1",
org.eclipse.ui.editors;bundle-version="3.10.1",
- org.antlr.runtime;bundle-version="3.2.0"
+ org.antlr.runtime;bundle-version="3.2.0",
+ org.eclipse.ui.forms;bundle-version="3.7.1"
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-Activator: io.sarl.lang.ui.internal.LangActivator
Export-Package: io.sarl.lang.ide,
io.sarl.lang.ide.contentassist.antlr,
io.sarl.lang.ide.contentassist.antlr.internal,
io.sarl.lang.ui;x-friends:="io.sarl.lang.ui.tests",
+ io.sarl.lang.ui.bugfixes.pending.xtexteclipse282,
io.sarl.lang.ui.builder,
io.sarl.lang.ui.codebuilder,
io.sarl.lang.ui.contentassist,
@@ -36,6 +38,9 @@ Export-Package: io.sarl.lang.ide,
io.sarl.lang.ui.contentassist.javadoc,
io.sarl.lang.ui.contentassist.templates,
io.sarl.lang.ui.editor,
+ io.sarl.lang.ui.generator.extra,
+ io.sarl.lang.ui.generator.extra.preferences,
+ io.sarl.lang.ui.generator.extra.properties,
io.sarl.lang.ui.highlighting,
io.sarl.lang.ui.hover,
io.sarl.lang.ui.hyperlinking,
diff --git a/main/coreplugins/io.sarl.lang.ui/OSGI-INF/l10n/bundle.properties b/main/coreplugins/io.sarl.lang.ui/OSGI-INF/l10n/bundle.properties
index 7f6c684039..552e5cc040 100644
--- a/main/coreplugins/io.sarl.lang.ui/OSGI-INF/l10n/bundle.properties
+++ b/main/coreplugins/io.sarl.lang.ui/OSGI-INF/l10n/bundle.properties
@@ -38,3 +38,4 @@ sarlContext.description = Editing SARL Source Context
sarlContext.name = Editing SARL Source
sarl.rename.participant.packageFolder = SARL Package Folder Rename
sarl.rename.participant.file = SARL Script File Rename
+extraGenerators = Extra-Language Generators
\ No newline at end of file
diff --git a/main/coreplugins/io.sarl.lang.ui/icons/experimental.png b/main/coreplugins/io.sarl.lang.ui/icons/experimental.png
new file mode 100644
index 0000000000..5775adb97b
Binary files /dev/null and b/main/coreplugins/io.sarl.lang.ui/icons/experimental.png differ
diff --git a/main/coreplugins/io.sarl.lang.ui/plugin.xml b/main/coreplugins/io.sarl.lang.ui/plugin.xml
index 89200a3917..2a058ee4c8 100644
--- a/main/coreplugins/io.sarl.lang.ui/plugin.xml
+++ b/main/coreplugins/io.sarl.lang.ui/plugin.xml
@@ -647,4 +647,6 @@
-
+
+
+
diff --git a/main/coreplugins/io.sarl.lang.ui/schema/extraGenerators.exsd b/main/coreplugins/io.sarl.lang.ui/schema/extraGenerators.exsd
new file mode 100644
index 0000000000..ce91f2ab32
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/schema/extraGenerators.exsd
@@ -0,0 +1,148 @@
+
+
+
+
+
+
+
+
+ Provide a generator for extra-languages to the standard SARL compiler.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fully qualified name of the class that implements an extra language generator, sub-type of IExtraLanguageGeneratorProvider.
+ The class name may be prefixed by the plugin factory.
+
+
+
+
+
+
+
+
+
+ Fully qualified name of the class that implements an extra language validator, sub-type of IExtraLanguageValidatorProvider.
+ The class name may be prefixed by the plugin factory.
+
+
+
+
+
+
+
+
+
+ Fully qualified name of the class that implements an extra language configuration provider, sub-type of IOutputConfigurationProvider.
+ The class name may be prefixed by the plugin factory.
+
+
+
+
+
+
+
+
+
+ Fully qualified name of the class that implements a preference initializer for an extra language generator, sub-type of IPreferenceStoreInitializer.
+ The class name may be prefixed by the plugin factory.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0.6.0
+
+
+
+
+
+
+
+
+ Following is an example definition of an execution environment and analyzer.
+<p>
+<pre>
+<extension point="io.sarl.lang.extraGenerators">
+ <extraGenerator
+ class="com.example.MyGenerator"/>
+</extension>
+</pre>
+</p>
+
+
+
+
+
+
+
+
+
+
+ Copyright 2017 the original authors and 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.
+
+
+
+
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/SARLUiConfig.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/SARLUiConfig.java
new file mode 100644
index 0000000000..e6b3b1809b
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/SARLUiConfig.java
@@ -0,0 +1,47 @@
+/*
+ * $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.ui;
+
+
+/**
+ * Provides the constants for the SARL projects.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+public final class SARLUiConfig {
+
+ /** Namespace for the extension points.
+ */
+ public static final String NAMESPACE = "io.sarl.lang.ui"; //$NON-NLS-1$
+
+ /** Extension point for extra language generators.
+ */
+ public static final String EXTENSION_POINT_EXTRA_LANGUAGE_GENERATORS = "extraGenerators"; //$NON-NLS-1$
+
+ private SARLUiConfig() {
+ //
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/SARLUiModule.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/SARLUiModule.java
index ceb7e17ff0..164c1f4881 100644
--- a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/SARLUiModule.java
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/SARLUiModule.java
@@ -27,12 +27,31 @@
import com.google.inject.Provider;
import com.google.inject.name.Names;
import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.eclipse.xtend.core.compiler.XtendGenerator;
+import org.eclipse.xtext.builder.preferences.BuilderConfigurationBlock;
+import org.eclipse.xtext.generator.IGenerator;
+import org.eclipse.xtext.generator.IGenerator2;
+import org.eclipse.xtext.generator.IOutputConfigurationProvider;
+import org.eclipse.xtext.service.SingletonBinding;
import org.eclipse.xtext.ui.editor.XtextEditor;
import org.eclipse.xtext.ui.editor.autoedit.AbstractEditStrategy;
import org.eclipse.xtext.validation.IssueSeveritiesProvider;
+import io.sarl.lang.bugfixes.pending.bug621.Bug621SARLExtraLanguageValidator;
+import io.sarl.lang.generator.extra.ExtraLanguageFeatureNameConverter.FeatureNameConverterRuleReader;
+import io.sarl.lang.generator.extra.ExtraLanguageSupportGenerator;
+import io.sarl.lang.generator.extra.ExtraLanguageTypeConverter.TypeConverterRuleReader;
+import io.sarl.lang.generator.extra.IExtraLanguageGeneratorProvider;
+import io.sarl.lang.ui.bugfixes.pending.xtexteclipse282.Issue282BuilderConfigurationBlock;
+import io.sarl.lang.ui.generator.extra.ExtensionPointExtraLanguageGeneratorProvider;
+import io.sarl.lang.ui.generator.extra.ExtensionPointExtraLanguageOutputConfigurationProvider;
+import io.sarl.lang.ui.generator.extra.ExtensionPointExtraLanguageValidatorProvider;
+import io.sarl.lang.ui.generator.extra.preferences.PreferenceBasedFeatureNameConverterRuleReader;
+import io.sarl.lang.ui.generator.extra.preferences.PreferenceBasedTypeConverterRuleReader;
import io.sarl.lang.ui.validation.UIConfigurableIssueSeveritiesProvider;
import io.sarl.lang.validation.IConfigurableIssueSeveritiesProvider;
+import io.sarl.lang.validation.SARLValidator;
+import io.sarl.lang.validation.extra.IExtraLanguageValidatorProvider;
/**
* Use this class to register components to be used within the IDE.
@@ -96,6 +115,9 @@ public void configure(Binder binder) {
binder.bind(UIConfigurableIssueSeveritiesProvider.class).toProvider(provider);
binder.bind(IssueSeveritiesProvider.class).toProvider(provider);
binder.bind(IConfigurableIssueSeveritiesProvider.class).toProvider(provider);
+ // Configure the extra generator/validator provider.
+ binder.bind(IGenerator2.class).annotatedWith(Names.named(ExtraLanguageSupportGenerator.MAIN_GENERATOR_NAME))
+ .to(XtendGenerator.class);
}
public void configureDebugMode(Binder binder) {
@@ -108,4 +130,41 @@ public void configureDebugMode(Binder binder) {
.to("io.sarl.lang.ui.scoping.SARLEditorScope"); //$NON-NLS-1$
}
+ /** TODO: Remove when xtext-eclipse/282 is fixed.
+ * {@inheritDoc}
+ */
+ @Override
+ public Class extends BuilderConfigurationBlock> bindBuilderConfigurationBlock() {
+ return Issue282BuilderConfigurationBlock.class;
+ }
+
+ public Class extends IOutputConfigurationProvider> bindIOutputConfigurationProvider() {
+ return ExtensionPointExtraLanguageOutputConfigurationProvider.class;
+ }
+
+ public Class extends IGenerator> bindIGenerator() {
+ return ExtraLanguageSupportGenerator.class;
+ }
+
+ @SingletonBinding(eager = true)
+ public Class extends SARLValidator> bindSARLValidator() {
+ return Bug621SARLExtraLanguageValidator.class;
+ }
+
+ public Class extends IExtraLanguageGeneratorProvider> bindIExtraLanguageGeneratorProvider() {
+ return ExtensionPointExtraLanguageGeneratorProvider.class;
+ }
+
+ public Class extends IExtraLanguageValidatorProvider> bindIExtraLanguageValidatorProvider() {
+ return ExtensionPointExtraLanguageValidatorProvider.class;
+ }
+
+ public Class extends TypeConverterRuleReader> bindTypeConverterRuleReader() {
+ return PreferenceBasedTypeConverterRuleReader.class;
+ }
+
+ public Class extends FeatureNameConverterRuleReader> bindFeatureNameConverterRuleReader() {
+ return PreferenceBasedFeatureNameConverterRuleReader.class;
+ }
+
}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/bugfixes/pending/xtexteclipse282/Issue282BuilderConfigurationBlock.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/bugfixes/pending/xtexteclipse282/Issue282BuilderConfigurationBlock.java
new file mode 100644
index 0000000000..5b73e4506a
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/bugfixes/pending/xtexteclipse282/Issue282BuilderConfigurationBlock.java
@@ -0,0 +1,105 @@
+/*
+ * $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.ui.bugfixes.pending.xtexteclipse282;
+
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.layout.PixelConverter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.forms.widgets.ExpandableComposite;
+import org.eclipse.xtext.builder.internal.Activator;
+import org.eclipse.xtext.generator.OutputConfiguration;
+import org.eclipse.xtext.ui.preferences.ScrolledPageContent;
+
+import io.sarl.lang.ui.preferences.SARLBuilderConfigurationBlock;
+
+/** See xtext-eclipse/#282: Add getOutputConfiguration function in BuilderConfigurationBlock.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @see "https://github.com/eclipse/xtext-eclipse/pull/282"
+ */
+public class Issue282BuilderConfigurationBlock extends SARLBuilderConfigurationBlock {
+
+ @Override
+ @SuppressWarnings("checkstyle:magicnumber")
+ protected Control doCreateContents(Composite parent) {
+ final PixelConverter pixelConverter = new PixelConverter(parent);
+ setShell(parent.getShell());
+ final Composite mainComp = new Composite(parent, SWT.NONE);
+ mainComp.setFont(parent.getFont());
+ final GridLayout layout = new GridLayout();
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ mainComp.setLayout(layout);
+ final Composite othersComposite = createBuildPathTabContent(mainComp);
+ final GridData gridData = new GridData(GridData.FILL, GridData.FILL, true, true);
+ gridData.heightHint = pixelConverter.convertHeightInCharsToPixels(20);
+ othersComposite.setLayoutData(gridData);
+ validateSettings(null, null, null);
+ return mainComp;
+ }
+
+ private Composite createBuildPathTabContent(Composite parent) {
+ final int columns = 3;
+ final ScrolledPageContent pageContent = new ScrolledPageContent(parent);
+ final GridLayout layout = new GridLayout();
+ layout.numColumns = columns;
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+
+ final Composite composite = pageContent.getBody();
+ composite.setLayout(layout);
+ String label = org.eclipse.xtext.builder.preferences.Messages.BuilderConfigurationBlock_GeneralSection_Label;
+ ExpandableComposite excomposite = createStyleSection(composite, label, columns);
+
+ Composite othersComposite = new Composite(excomposite, SWT.NONE);
+ excomposite.setClient(othersComposite);
+ othersComposite.setLayout(new GridLayout(columns, false));
+
+ createGeneralSectionItems(othersComposite);
+
+ final Set outputConfigurations = getOutputConfigurations(getProject());
+
+ for (final OutputConfiguration outputConfiguration : outputConfigurations) {
+ label = outputConfiguration.getDescription();
+ excomposite = createStyleSection(composite, label, columns);
+ othersComposite = new Composite(excomposite, SWT.NONE);
+ excomposite.setClient(othersComposite);
+ othersComposite.setLayout(new GridLayout(columns, false));
+
+ createOutputSectionItems(othersComposite, outputConfiguration);
+ }
+ registerKey(getIsProjectSpecificPropertyKey(getPropertyPrefix()));
+ final IDialogSettings section = Activator.getDefault().getDialogSettings().getSection(SETTINGS_SECTION_NAME);
+ restoreSectionExpansionStates(section);
+ return pageContent;
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/ExtensionPointExtraLanguageGeneratorProvider.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/ExtensionPointExtraLanguageGeneratorProvider.java
new file mode 100644
index 0000000000..c70d33802e
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/ExtensionPointExtraLanguageGeneratorProvider.java
@@ -0,0 +1,83 @@
+/*
+ * $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.ui.generator.extra;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.xtext.generator.IGenerator2;
+import org.eclipse.xtext.generator.IGeneratorContext;
+
+import io.sarl.lang.generator.extra.IExtraLanguageGeneratorProvider;
+import io.sarl.lang.ui.SARLUiConfig;
+import io.sarl.lang.ui.internal.LangActivator;
+
+/** Implementation of the provider of the extra language generators that replies no generator.
+ *
+ * The generators are provided by the extension points.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public class ExtensionPointExtraLanguageGeneratorProvider implements IExtraLanguageGeneratorProvider {
+
+ private static final String EXTENSION_POINT_GENERATOR_ATTRIBUTE = "generator"; //$NON-NLS-1$
+
+ @Override
+ public Iterable getGenerators(IGeneratorContext context, Resource resource) {
+ final List generators = new ArrayList<>();
+ final IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(
+ SARLUiConfig.NAMESPACE, SARLUiConfig.EXTENSION_POINT_EXTRA_LANGUAGE_GENERATORS);
+ if (extensionPoint != null) {
+ Object obj;
+ for (final IConfigurationElement element : extensionPoint.getConfigurationElements()) {
+ //final String typeName = element.getAttribute(EXTENSION_POINT_GENERATOR_ATTRIBUTE);
+ try {
+ obj = element.createExecutableExtension(EXTENSION_POINT_GENERATOR_ATTRIBUTE);
+ if (obj instanceof IExtraLanguageGeneratorProvider) {
+ for (final IGenerator2 gen : ((IExtraLanguageGeneratorProvider) obj).getGenerators(context, resource)) {
+ generators.add(gen);
+ }
+ }
+ } catch (CoreException exception) {
+ LangActivator.getInstance().getLog().log(new Status(
+ IStatus.WARNING,
+ LangActivator.getInstance().getBundle().getSymbolicName(),
+ exception.getLocalizedMessage(),
+ exception));
+ }
+ }
+ }
+ return generators;
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/ExtensionPointExtraLanguageOutputConfigurationProvider.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/ExtensionPointExtraLanguageOutputConfigurationProvider.java
new file mode 100644
index 0000000000..1229bf098f
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/ExtensionPointExtraLanguageOutputConfigurationProvider.java
@@ -0,0 +1,80 @@
+/*
+ * $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.ui.generator.extra;
+
+import java.util.Set;
+
+import com.google.inject.Singleton;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.xtext.generator.IOutputConfigurationProvider;
+import org.eclipse.xtext.generator.OutputConfiguration;
+
+import io.sarl.lang.generator.SarlOutputConfigurationProvider;
+import io.sarl.lang.ui.SARLUiConfig;
+import io.sarl.lang.ui.internal.LangActivator;
+
+
+/** Provide the output configuration from the SARL code and the extra languages.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+@Singleton
+public class ExtensionPointExtraLanguageOutputConfigurationProvider extends SarlOutputConfigurationProvider {
+
+ private static final String EXTENSION_POINT_CONFIGURATION_ATTRIBUTE = "configuration"; //$NON-NLS-1$
+
+ @Override
+ public Set getOutputConfigurations() {
+ final Set configurations = super.getOutputConfigurations();
+ final IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(
+ SARLUiConfig.NAMESPACE, SARLUiConfig.EXTENSION_POINT_EXTRA_LANGUAGE_GENERATORS);
+ if (extensionPoint != null) {
+ Object obj;
+ for (final IConfigurationElement element : extensionPoint.getConfigurationElements()) {
+ try {
+ obj = element.createExecutableExtension(EXTENSION_POINT_CONFIGURATION_ATTRIBUTE);
+ if (obj instanceof IOutputConfigurationProvider) {
+ final IOutputConfigurationProvider provider = (IOutputConfigurationProvider) obj;
+ configurations.addAll(provider.getOutputConfigurations());
+ }
+ } catch (CoreException exception) {
+ LangActivator.getInstance().getLog().log(new Status(
+ IStatus.WARNING,
+ LangActivator.getInstance().getBundle().getSymbolicName(),
+ exception.getLocalizedMessage(),
+ exception));
+ }
+ }
+ }
+ return configurations;
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/ExtensionPointExtraLanguagePreferenceInitializer.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/ExtensionPointExtraLanguagePreferenceInitializer.java
new file mode 100644
index 0000000000..b0d04f23ae
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/ExtensionPointExtraLanguagePreferenceInitializer.java
@@ -0,0 +1,75 @@
+/*
+ * $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.ui.generator.extra;
+
+import com.google.inject.Singleton;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess;
+import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreInitializer;
+
+import io.sarl.lang.ui.SARLUiConfig;
+import io.sarl.lang.ui.internal.LangActivator;
+
+
+/** Provide the output configuration from the SARL code and the extra languages.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+@Singleton
+public class ExtensionPointExtraLanguagePreferenceInitializer implements IPreferenceStoreInitializer {
+
+ private static final String EXTENSION_POINT_PREFERENCE_INITIALIZER_ATTRIBUTE = "preferences"; //$NON-NLS-1$
+
+ @Override
+ public void initialize(IPreferenceStoreAccess access) {
+ final IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(
+ SARLUiConfig.NAMESPACE, SARLUiConfig.EXTENSION_POINT_EXTRA_LANGUAGE_GENERATORS);
+ if (extensionPoint != null) {
+ Object obj;
+ for (final IConfigurationElement element : extensionPoint.getConfigurationElements()) {
+ try {
+ obj = element.createExecutableExtension(EXTENSION_POINT_PREFERENCE_INITIALIZER_ATTRIBUTE);
+ if (obj instanceof IPreferenceStoreInitializer) {
+ final IPreferenceStoreInitializer provider = (IPreferenceStoreInitializer) obj;
+ provider.initialize(access);
+ }
+ } catch (CoreException exception) {
+ LangActivator.getInstance().getLog().log(new Status(
+ IStatus.WARNING,
+ LangActivator.getInstance().getBundle().getSymbolicName(),
+ exception.getLocalizedMessage(),
+ exception));
+ }
+ }
+ }
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/ExtensionPointExtraLanguageValidatorProvider.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/ExtensionPointExtraLanguageValidatorProvider.java
new file mode 100644
index 0000000000..5fa2abd77c
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/ExtensionPointExtraLanguageValidatorProvider.java
@@ -0,0 +1,81 @@
+/*
+ * $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.ui.generator.extra;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.ecore.EValidator;
+import org.eclipse.emf.ecore.resource.Resource;
+
+import io.sarl.lang.ui.SARLUiConfig;
+import io.sarl.lang.ui.internal.LangActivator;
+import io.sarl.lang.validation.extra.IExtraLanguageValidatorProvider;
+
+/** Implementation of the provider of the extra language generators that replies no generator.
+ *
+ * The generators are provided by the extension points.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public class ExtensionPointExtraLanguageValidatorProvider implements IExtraLanguageValidatorProvider {
+
+ private static final String EXTENSION_POINT_VALIDATOR_ATTRIBUTE = "validator"; //$NON-NLS-1$
+
+ @Override
+ public Iterable getValidators(Resource resource) {
+ final List validators = new ArrayList<>();
+ final IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(
+ SARLUiConfig.NAMESPACE, SARLUiConfig.EXTENSION_POINT_EXTRA_LANGUAGE_GENERATORS);
+ if (extensionPoint != null) {
+ Object obj;
+ for (final IConfigurationElement element : extensionPoint.getConfigurationElements()) {
+ try {
+ obj = element.createExecutableExtension(EXTENSION_POINT_VALIDATOR_ATTRIBUTE);
+ if (obj instanceof IExtraLanguageValidatorProvider) {
+ for (final EValidator validator : ((IExtraLanguageValidatorProvider) obj).getValidators(resource)) {
+ validators.add(validator);
+ }
+ }
+ } catch (CoreException exception) {
+ LangActivator.getInstance().getLog().log(new Status(
+ IStatus.WARNING,
+ LangActivator.getInstance().getBundle().getSymbolicName(),
+ exception.getLocalizedMessage(),
+ exception));
+ }
+ }
+ }
+ return validators;
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/ProjectAdapter.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/ProjectAdapter.java
new file mode 100644
index 0000000000..97b512b8f5
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/ProjectAdapter.java
@@ -0,0 +1,80 @@
+/*
+ * $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.ui.generator.extra;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+/** Adapter for retreiving a project.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public class ProjectAdapter extends AdapterImpl {
+
+ private final IProject project;
+
+ /** Constructor.
+ *
+ * @param project the project.
+ */
+ public ProjectAdapter(IProject project) {
+ this.project = project;
+ }
+
+ @Override
+ public boolean isAdapterForType(Object type) {
+ return ProjectAdapter.class.equals(type);
+ }
+
+ /** Replies the project.
+ *
+ * @return the project.
+ */
+ public IProject getProject() {
+ return this.project;
+ }
+
+ /** Get the project associated to the resource.
+ *
+ * @param resource the resource
+ * @return the project.
+ */
+ public static IProject getProject(Resource resource) {
+ ProjectAdapter adapter = (ProjectAdapter) EcoreUtil.getAdapter(resource.getResourceSet().eAdapters(), ProjectAdapter.class);
+ if (adapter == null) {
+ final String platformString = resource.getURI().toPlatformString(true);
+ final IProject project = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(platformString)).getProject();
+ adapter = new ProjectAdapter(project);
+ resource.getResourceSet().eAdapters().add(adapter);
+ }
+ return adapter.getProject();
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/preferences/ExtraLanguagePreferenceAccess.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/preferences/ExtraLanguagePreferenceAccess.java
new file mode 100644
index 0000000000..89102d9553
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/preferences/ExtraLanguagePreferenceAccess.java
@@ -0,0 +1,335 @@
+/*
+ * $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.ui.generator.extra.preferences;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.StringTokenizer;
+
+import com.google.inject.Inject;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess;
+import org.eclipse.xtext.ui.editor.preferences.PreferenceConstants;
+import org.eclipse.xtext.ui.editor.preferences.PreferenceStoreAccessImpl;
+import org.eclipse.xtext.xbase.lib.Procedures.Procedure2;
+
+import io.sarl.lang.generator.extra.IExtraLanguageConversionInitializer;
+import io.sarl.lang.ui.generator.extra.properties.AbstractGeneratorConfigurationBlock;
+
+/** Preferences for the extra language generators.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public class ExtraLanguagePreferenceAccess {
+
+ /** Key for saving the enabling state of the extra language generator.
+ */
+ public static final String GENERATOR_PREFERENCE_TAG = "extraLanguageGenerator"; //$NON-NLS-1$
+
+ /** Key for saving the enabling state of the extra language generator.
+ */
+ public static final String ENABLED_PROPERTY = "enabled"; //$NON-NLS-1$
+
+ /** Key for saving the type conversions.
+ */
+ public static final String TYPE_CONVERSION_PROPERTY = "typeConversions"; //$NON-NLS-1$
+
+ /** Key for saving the feature name conversions.
+ */
+ public static final String FEATURE_NAME_CONVERSION_PROPERTY = "featureNameConversions"; //$NON-NLS-1$
+
+ private static final String IS_PROJECT_SPECIFIC = "is_project_specific"; //$NON-NLS-1$
+
+ private static final String PREFERENCE_SEPARATOR = ":"; //$NON-NLS-1$
+
+ private PreferenceStoreAccessImpl preferenceStoreAccess;
+
+ /** Change the preference accessor.
+ *
+ * The parameter is a preference store implementation in order to have access to the correct preference set.
+ * It is an implementation choice from {@link OptionsConfigurationBlock}.
+ *
+ * @param preferenceStoreAccess the accessor.
+ */
+ @Inject
+ public void setPreferenceStoreAccess(PreferenceStoreAccessImpl preferenceStoreAccess) {
+ this.preferenceStoreAccess = preferenceStoreAccess;
+ }
+
+ /** Replies the preference accessor.
+ *
+ * @return the accessor.
+ */
+ @Inject
+ public IPreferenceStoreAccess getPreferenceStoreAccess() {
+ return this.preferenceStoreAccess;
+ }
+
+ /** Create a preference key according to the Xtext option block standards.
+ *
+ * @param pluginID the identifier of the plugin of the generator.
+ * @param preferenceName the name of the preference.
+ * @return the key.
+ */
+ private static String getXtextKey(String pluginID, String preferenceName) {
+ return GENERATOR_PREFERENCE_TAG + PreferenceConstants.SEPARATOR + pluginID
+ + PreferenceConstants.SEPARATOR + preferenceName;
+ }
+
+ /** Create a preference key.
+ *
+ * @param pluginID the identifier of the plugin of the generator.
+ * @param preferenceName the name of the preference.
+ * @return the key.
+ */
+ public static String getPrefixedKey(String pluginID, String preferenceName) {
+ return getXtextKey(getPropertyPrefix(pluginID), preferenceName);
+ }
+
+ /** Replies the preference value from the given store.
+ *
+ * @param store the preference storE.
+ * @param pluginID the identifier of the plugin of the generator.
+ * @param preferenceName the name of the preference.
+ * @return the key.
+ */
+ public static String getString(IPreferenceStore store, String pluginID, String preferenceName) {
+ return store.getString(getPrefixedKey(pluginID, preferenceName));
+ }
+
+ /** Replies the preference value from the given store.
+ *
+ * @param store the preference storE.
+ * @param pluginID the identifier of the plugin of the generator.
+ * @param preferenceName the name of the preference.
+ * @return the key.
+ */
+ public static boolean getBoolean(IPreferenceStore store, String pluginID, String preferenceName) {
+ return store.getBoolean(getPrefixedKey(pluginID, preferenceName));
+ }
+
+ /** Compute a property prefix.
+ *
+ * @param pluginID the plugin ID.
+ * @return the property prefix.
+ */
+ public static String getPropertyPrefix(String pluginID) {
+ if (pluginID == null) {
+ return null;
+ }
+ return pluginID.replaceAll("[^a-zA-Z0-9_.]+", "_"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /** Replies the writable preference store to be used for the extra language generators.
+ *
+ *
This function does not test if the given project has a specific configuration.
+ * The project's configuration is systematically replied.
+ *
+ * @param project the context. If {@code null}, the global context is assumed.
+ * @return the modifiable preference store.
+ * @see #getPreferenceStore(IProject)
+ */
+ public IPreferenceStore getWritablePreferenceStore(IProject project) {
+ return getPreferenceStoreAccess().getWritablePreferenceStore(project);
+ }
+
+ /** Replies the readable preference store to be used for the extra language generators.
+ *
+ *
This function does not test if the given project has a specific configuration.
+ * The project's configuration is systematically replied.
+ *
+ * @param project the context. If {@code null}, the global context is assumed.
+ * @return the unmodifiable preference store.
+ * @see #getWritablePreferenceStore(IProject)
+ */
+ public IPreferenceStore getPreferenceStore(IProject project) {
+ return getPreferenceStoreAccess().getContextPreferenceStore(project);
+ }
+
+ /** Replies if the project has specific configuration for extra language generation provided by the given plugin.
+ *
+ *
This code is copied from {@link AbstractGeneratorConfigurationBlock} and its super types.
+ *
+ * @param pluginID the identifier of the extra language generator plugin.
+ * @param project the context.
+ * @return {@code true} if the given project has a specific configuration. {@code false} if
+ * the general configuration should be used.
+ */
+ public boolean hasProjectSpecificOptions(String pluginID, IProject project) {
+ final IPreferenceStore store = getWritablePreferenceStore(project);
+ // Compute the key
+ String key = IS_PROJECT_SPECIFIC;
+ if (pluginID != null) {
+ key = getPropertyPrefix(pluginID) + "." + IS_PROJECT_SPECIFIC; //$NON-NLS-1$
+ }
+ // backward compatibility
+ final boolean oldSettingsUsed = store.getBoolean(IS_PROJECT_SPECIFIC);
+ final boolean newSettingsValue = store.getBoolean(key);
+ if (oldSettingsUsed && !newSettingsValue) {
+ store.setValue(key, true);
+ return true;
+ }
+ return newSettingsValue;
+ }
+
+ /** Filter the project according to the specific configuration.
+ *
+ *
If the given project has a specific configuration, it is replied.
+ * Otherwise, {@code null} is replied.
+ *
+ * @param pluginID the identifier of the extra language generator plugin.
+ * @param project the context. If {@code null}, the global context is assumed.
+ * @return the unmodifiable preference store.
+ */
+ public IProject ifSpecificConfiguration(String pluginID, IProject project) {
+ if (project != null && hasProjectSpecificOptions(pluginID, project)) {
+ return project;
+ }
+ return null;
+ }
+
+ /** Replies if the extr language generator is enabled.
+ *
+ * @param pluginID the identifier of the plugin that is associated to the generator.
+ * @param project the context.
+ * @return {@code true} if it is enabled.
+ */
+ public boolean isGeneratorEnabled(String pluginID, IProject project) {
+ final IProject prj = ifSpecificConfiguration(pluginID, project);
+ final IPreferenceStore store = getPreferenceStore(prj);
+ return getBoolean(store, pluginID, ENABLED_PROPERTY);
+ }
+
+ /** Parse the given input which is the preference string representation.
+ *
+ * @param input the string representation from the preferences.
+ * @param output the function to call for saving the parsed element. The first parameter is the element to be
+ * converted. The second parameter is the target string.
+ * @return {@code true} if a data was parsed. {@code false} if no value was parsed.
+ */
+ public static boolean parseConverterPreferenceValue(String input, Procedure2 output) {
+ final StringTokenizer tokenizer = new StringTokenizer(input, PREFERENCE_SEPARATOR);
+ String key = null;
+ boolean foundValue = false;
+ while (tokenizer.hasMoreTokens()) {
+ final String token = tokenizer.nextToken();
+ if (key != null) {
+ output.apply(key, token);
+ foundValue = true;
+ key = null;
+ } else {
+ key = token;
+ }
+ }
+ return foundValue;
+ }
+
+ /** Generate the string representation of the type conversions in order to be
+ * saved into the preferences.
+ *
+ * @param input the type conversions.
+ * @return the string representation.
+ */
+ public static String toConverterPreferenceValue(Iterator input) {
+ final StringBuilder builder = new StringBuilder();
+ while (input.hasNext()) {
+ final String value = input.next();
+ if (builder.length() > 0) {
+ builder.append(PREFERENCE_SEPARATOR);
+ }
+ builder.append(value);
+ }
+ return builder.toString();
+ }
+
+ /** Generate the string representation of the type conversions in order to be
+ * saved into the preferences.
+ *
+ * @param input the type conversions.
+ * @return the string representation.
+ */
+ public static String toConverterPreferenceValue(Map input) {
+ return toConverterPreferenceValue(new ConversionIterator(input));
+ }
+
+ /** Generate the string representation of the type conversions in order to be
+ * saved into the preferences.
+ *
+ * @param input the type conversions.
+ * @return the string representation.
+ */
+ public static String toConverterPreferenceValue(IExtraLanguageConversionInitializer input) {
+ final StringBuilder builder = new StringBuilder();
+ input.initializeConversions((baseName, source, target) -> {
+ if (builder.length() > 0) {
+ builder.append(PREFERENCE_SEPARATOR);
+ }
+ builder.append(source);
+ builder.append(PREFERENCE_SEPARATOR);
+ builder.append(target);
+ });
+ return builder.toString();
+ }
+
+ /** Iterator on conversions.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+ public static class ConversionIterator implements Iterator {
+
+ private final Iterator> entries;
+
+ /** Constructor.
+ *
+ * @param conversions the mapping definition.
+ */
+ public ConversionIterator(Map conversions) {
+ this.entries = conversions.entrySet().iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return this.entries.hasNext();
+ }
+
+ @Override
+ public String next() {
+ final Entry entry = this.entries.next();
+ final String source = entry.getKey();
+ final String target = entry.getValue();
+ return source + PREFERENCE_SEPARATOR + target;
+ }
+
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/preferences/PreferenceBasedFeatureNameConverterRuleReader.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/preferences/PreferenceBasedFeatureNameConverterRuleReader.java
new file mode 100644
index 0000000000..fc630eade6
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/preferences/PreferenceBasedFeatureNameConverterRuleReader.java
@@ -0,0 +1,76 @@
+/*
+ * $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.ui.generator.extra.preferences;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.inject.Inject;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.xtext.xbase.lib.Pair;
+
+import io.sarl.lang.generator.extra.ExtraLanguageFeatureNameConverter;
+import io.sarl.lang.generator.extra.ExtraLanguageFeatureNameConverter.FeatureNameConverterRuleReader;
+import io.sarl.lang.generator.extra.ExtraLanguageFeatureNameConverter.FeaturePattern;
+import io.sarl.lang.generator.extra.ExtraLanguageFeatureNameConverter.FeatureReplacement;
+import io.sarl.lang.generator.extra.IExtraLanguageGeneratorContext;
+import io.sarl.lang.ui.generator.extra.ProjectAdapter;
+
+/** Reader of the feature name conversion rules from the preferences.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public class PreferenceBasedFeatureNameConverterRuleReader extends FeatureNameConverterRuleReader {
+
+ @Inject
+ private ExtraLanguagePreferenceAccess preferences;
+
+ @Override
+ public boolean initializeConversions(Map>> result,
+ String pluginID, IExtraLanguageGeneratorContext context) {
+ if (context != null) {
+ final IProject project = ProjectAdapter.getProject(context.getResource());
+ final IPreferenceStore store = this.preferences.getPreferenceStore(project);
+ final String rawValue = ExtraLanguagePreferenceAccess.getString(store, pluginID,
+ ExtraLanguagePreferenceAccess.FEATURE_NAME_CONVERSION_PROPERTY);
+ return ExtraLanguagePreferenceAccess.parseConverterPreferenceValue(rawValue, (source, target) -> {
+ final String shortName = FeaturePattern.simpleName(source);
+ final char key = ExtraLanguageFeatureNameConverter.getKey(shortName);
+ List> internalStruct = result.get(key);
+ if (internalStruct == null) {
+ internalStruct = new ArrayList<>();
+ result.put(key, internalStruct);
+ }
+ internalStruct.add(new Pair<>(new FeaturePattern(source), new FeatureReplacement(target)));
+ });
+ }
+ return false;
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/preferences/PreferenceBasedTypeConverterRuleReader.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/preferences/PreferenceBasedTypeConverterRuleReader.java
new file mode 100644
index 0000000000..209ac50c6d
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/preferences/PreferenceBasedTypeConverterRuleReader.java
@@ -0,0 +1,62 @@
+/*
+ * $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.ui.generator.extra.preferences;
+
+import java.util.Map;
+
+import javax.inject.Inject;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jface.preference.IPreferenceStore;
+
+import io.sarl.lang.generator.extra.ExtraLanguageTypeConverter.TypeConverterRuleReader;
+import io.sarl.lang.generator.extra.IExtraLanguageGeneratorContext;
+import io.sarl.lang.ui.generator.extra.ProjectAdapter;
+
+/** Reader of the type conversion rules from the preferences.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public class PreferenceBasedTypeConverterRuleReader extends TypeConverterRuleReader {
+
+ @Inject
+ private ExtraLanguagePreferenceAccess preferences;
+
+ @Override
+ public boolean initializeConversions(Map result,
+ String pluginID, IExtraLanguageGeneratorContext context) {
+ if (context != null) {
+ final IProject project = ProjectAdapter.getProject(context.getResource());
+ final IPreferenceStore store = this.preferences.getPreferenceStore(project);
+ final String rawValue = ExtraLanguagePreferenceAccess.getString(store, pluginID,
+ ExtraLanguagePreferenceAccess.TYPE_CONVERSION_PROPERTY);
+ return ExtraLanguagePreferenceAccess.parseConverterPreferenceValue(rawValue,
+ (source, target) -> result.put(source, target));
+ }
+ return false;
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/AbstractConversionTable.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/AbstractConversionTable.java
new file mode 100644
index 0000000000..27b5ba6b3a
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/AbstractConversionTable.java
@@ -0,0 +1,1013 @@
+/*
+ * $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.ui.generator.extra.properties;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+
+import org.eclipse.debug.internal.ui.SWTFactory;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.search.IJavaSearchConstants;
+import org.eclipse.jdt.internal.ui.JavaUIMessages;
+import org.eclipse.jdt.internal.ui.dialogs.OpenTypeSelectionDialog;
+import org.eclipse.jdt.ui.ISharedImages;
+import org.eclipse.jdt.ui.JavaUI;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.viewers.BaseLabelProvider;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.DialogCellEditor;
+import org.eclipse.jface.viewers.ICellModifier;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.xtext.util.Strings;
+import org.eclipse.xtext.xbase.lib.Pair;
+
+import io.sarl.lang.ui.generator.extra.preferences.ExtraLanguagePreferenceAccess;
+
+/** Abstract implementation of a table for conversion definition.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+@SuppressWarnings({"checkstyle:classdataabstractioncoupling", "checkstyle:classfanoutcomplexity"})
+public abstract class AbstractConversionTable extends AbstractExtraControl {
+
+ /** Propery name for the source column.
+ */
+ protected static final String SOURCE_COLUMN_PROPERTY = "source"; //$NON-NLS-1$
+
+ /** Propery name for the target column.
+ */
+ protected static final String TARGET_COLUMN_PROPERTY = "target"; //$NON-NLS-1$
+
+ private static final int WIDTH_HINT = 350;
+
+ private static final int HEIGHT_HINT = 250;
+
+ private static final int DEFAULT_WIDTH = WIDTH_HINT / 2;
+
+ private final boolean isSortedElements;
+
+ private final LinkedList conversions = new LinkedList<>();
+
+ private Table table;
+
+ private TableViewer list;
+
+ private CellEditor[] editors;
+
+ private ICellModifier cellModifier;
+
+ private Column sort = Column.SOURCE;
+
+ private Button removeButton;
+
+ private Button clearButton;
+
+ private Button moveTopButton;
+
+ private Button moveUpButton;
+
+ private Button moveDownButton;
+
+ private Button moveBottomButton;
+
+ /** Constructor.
+ *
+ * @param controller the controller.
+ * @param pluginID the identifier of the plugin.
+ * @param languageImage for the target language (16x16).
+ * @param preferenceStore the preference store to be used.
+ * @param sortedElements indicates if the elements in the table should be sorted.
+ */
+ AbstractConversionTable(IExtraControlController controller, String pluginID, Image languageImage,
+ IPreferenceStore preferenceStore, boolean sortedElements) {
+ super(controller, pluginID, languageImage, preferenceStore);
+ this.isSortedElements = sortedElements;
+ }
+
+ /** Replies the label of the source column.
+ *
+ * @return the label.
+ */
+ protected abstract String getSourceColumnLabel();
+
+ /** Replies the label of the target column.
+ *
+ * @return the label.
+ */
+ protected abstract String getTargetColumnLabel();
+
+ /** Replies the editor for the source column.
+ *
+ * @return the editor, or {@code null}.
+ */
+ protected abstract CellEditor createSourceColumnEditor();
+
+ /** Replies the editor for the target column.
+ *
+ * @return the editor, or {@code null}.
+ */
+ protected abstract CellEditor createTargetColumnEditor();
+
+ /** Replies the cell modifier for all the columns.
+ *
+ * @return the cell modifier, or {@code null}.
+ */
+ protected ICellModifier createCellModifier() {
+ return new CellModifier(this, SOURCE_COLUMN_PROPERTY, TARGET_COLUMN_PROPERTY);
+ }
+
+ /** Replies the content provider for all the cells.
+ *
+ * @return the cell content provider, never {@code null}.
+ */
+ protected IStructuredContentProvider createContentProvider() {
+ return new ContentProvider();
+ }
+
+ /** Replies the label provider for all the cells.
+ *
+ * @return the label content provider, never {@code null}.
+ */
+ protected ITableLabelProvider createLabelProvider() {
+ return new LabelProvider(getLanguageImage());
+ }
+
+ /** Replies the message to display as introduction.
+ *
+ * @return the introduction message, or {@code null} if there is no introduction message.
+ */
+ @SuppressWarnings("static-method")
+ protected String getIntroductionLabel() {
+ return null;
+ }
+
+ /** Create the table.
+ *
+ * @param parentComposite the parent.
+ * @param settings the dialog settings.
+ */
+ public void doCreate(Composite parentComposite, IDialogSettings settings) {
+ // Introduction
+ final String introductionMessage = getIntroductionLabel();
+ if (!Strings.isEmpty(introductionMessage)) {
+ final GridData gd = new GridData();
+ gd.grabExcessHorizontalSpace = true;
+ gd.horizontalAlignment = GridData.FILL_HORIZONTAL;
+ gd.horizontalSpan = 2;
+ final Label textWidget = new Label(parentComposite, SWT.WRAP);
+ textWidget.setLayoutData(gd);
+ textWidget.setText(introductionMessage);
+ textWidget.setFont(parentComposite.getFont());
+ }
+ //
+ final GridData gd = new GridData(GridData.FILL_BOTH);
+ gd.heightHint = HEIGHT_HINT;
+ gd.widthHint = WIDTH_HINT;
+ this.table = new Table(parentComposite, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
+ this.table.setLayoutData(gd);
+ this.table.setFont(parentComposite.getFont());
+ this.table.setHeaderVisible(true);
+ this.table.setLinesVisible(true);
+ this.table.setLinesVisible(true);
+
+ TableColumn column = new TableColumn(this.table, SWT.NULL);
+ column.setText(getSourceColumnLabel());
+ if (!this.isSortedElements) {
+ column.addSelectionListener(new SelectionAdapter() {
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+ sortBySourceColumn();
+ AbstractConversionTable.this.list.refresh(true);
+ }
+ });
+ }
+ column.setWidth(DEFAULT_WIDTH);
+
+ column = new TableColumn(this.table, SWT.NULL);
+ column.setText(getTargetColumnLabel());
+ if (!this.isSortedElements) {
+ column.addSelectionListener(new SelectionAdapter() {
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+ sortByTargetColumn();
+ AbstractConversionTable.this.list.refresh(true);
+ }
+ });
+ }
+ column.setWidth(DEFAULT_WIDTH);
+
+ this.list = new TableViewer(this.table);
+ this.list.setLabelProvider(createLabelProvider());
+ this.list.setContentProvider(createContentProvider());
+ this.list.setUseHashlookup(true);
+
+ this.list.addSelectionChangedListener((evt) -> enableButtons());
+
+ this.table.addKeyListener(new KeyAdapter() {
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public void keyPressed(KeyEvent event) {
+ if (event.character == SWT.DEL && event.stateMask == 0) {
+ if (AbstractConversionTable.this.removeButton.isEnabled()) {
+ removeCurrentTypeConversion();
+ }
+ }
+ }
+ });
+
+ this.editors = new CellEditor[2];
+ this.editors[0] = createSourceColumnEditor();
+ this.editors[1] = createTargetColumnEditor();
+ this.list.setCellEditors(this.editors);
+
+ this.cellModifier = createCellModifier();
+ this.list.setColumnProperties(new String[] {SOURCE_COLUMN_PROPERTY, TARGET_COLUMN_PROPERTY});
+ this.list.setCellModifier(this.cellModifier);
+
+ final Composite buttons = SWTFactory.createComposite(parentComposite, parentComposite.getFont(), 1, 1,
+ GridData.VERTICAL_ALIGN_BEGINNING, 0, 0);
+
+ final Button addButton = SWTFactory.createPushButton(buttons, Messages.AbstractConversionTable_0, null);
+ addButton.addListener(SWT.Selection, (evt) -> addTypeConversion(null, null, true));
+
+ this.removeButton = SWTFactory.createPushButton(buttons, Messages.AbstractConversionTable_1, null);
+ this.removeButton.addListener(SWT.Selection, (evt) -> removeCurrentTypeConversion());
+
+ this.clearButton = SWTFactory.createPushButton(buttons, Messages.AbstractConversionTable_2, null);
+ this.clearButton.addListener(SWT.Selection, (evt) -> removeAllTypeConversions());
+
+ if (this.isSortedElements) {
+ this.moveTopButton = SWTFactory.createPushButton(buttons, Messages.AbstractConversionTable_3, null);
+ this.moveTopButton.addListener(SWT.Selection, (evt) -> moveSelectionTop());
+
+ this.moveUpButton = SWTFactory.createPushButton(buttons, Messages.AbstractConversionTable_4, null);
+ this.moveUpButton.addListener(SWT.Selection, (evt) -> moveSelectionUp());
+
+ this.moveDownButton = SWTFactory.createPushButton(buttons, Messages.AbstractConversionTable_5, null);
+ this.moveDownButton.addListener(SWT.Selection, (evt) -> moveSelectionDown());
+
+ this.moveBottomButton = SWTFactory.createPushButton(buttons, Messages.AbstractConversionTable_6, null);
+ this.moveBottomButton.addListener(SWT.Selection, (evt) -> moveSelectionBottom());
+ }
+
+ SWTFactory.createVerticalSpacer(parentComposite, 1);
+
+ // Register the preference key(s)
+ registerKey(getPreferenceKey());
+
+ // Fill the content of the table
+ updateControls();
+
+ // Enable/disable the buttons
+ enableButtons();
+
+ // By default, sort by name
+ restoreColumnSettings(settings);
+ }
+
+ /** Replies the UI control that is embedded in this object.
+ *
+ * @return the control widget.
+ */
+ public Table getControl() {
+ return this.table;
+ }
+
+ /** Create a cell editor that enables to select a class.
+ *
+ * @return the cell editor.
+ */
+ protected CellEditor createClassCellEditor() {
+ return new DialogCellEditor(getControl()) {
+ @Override
+ protected Object openDialogBox(Control cellEditorWindow) {
+ final OpenTypeSelectionDialog dialog = new OpenTypeSelectionDialog(
+ getControl().getShell(),
+ false,
+ PlatformUI.getWorkbench().getProgressService(),
+ null,
+ IJavaSearchConstants.TYPE);
+ dialog.setTitle(JavaUIMessages.OpenTypeAction_dialogTitle);
+ dialog.setMessage(JavaUIMessages.OpenTypeAction_dialogMessage);
+ final int result = dialog.open();
+ if (result != IDialogConstants.OK_ID) {
+ return null;
+ }
+ final Object[] types = dialog.getResult();
+ if (types == null || types.length != 1 || !(types[0] instanceof IType)) {
+ return null;
+ }
+ final IType type = (IType) types[0];
+ final String name = type.getFullyQualifiedName();
+ return Strings.emptyIfNull(name);
+ }
+ };
+ }
+
+ /** Create a cell editor that enables to type text.
+ *
+ * @return the cell editor.
+ */
+ protected CellEditor createTextCellEditor() {
+ return new TextCellEditor(getControl());
+ }
+
+ /** Replies the key for saving the conversions into the preferences.
+ *
+ * @return the key.
+ */
+ protected abstract String getPreferenceKey();
+
+ @Override
+ public void updateControls() {
+ final IExtraControlController ctrl = getController();
+ final String preferenceName = getPreferenceKey();
+ final String rawValue = Strings.emptyIfNull(ctrl.getValue(preferenceName));
+ final List> conversions = new ArrayList<>();
+ ExtraLanguagePreferenceAccess.parseConverterPreferenceValue(rawValue,
+ (source, target) -> conversions.add(new Pair<>(source, target)));
+ setTypeConversions(conversions, false);
+ }
+
+ /**
+ * Enables the type conversion buttons based on selected items counts in the viewer.
+ */
+ private void enableButtons() {
+ final int itemCount = this.list.getTable().getItemCount();
+ final boolean hasElement = itemCount > 0;
+ IStructuredSelection selection;
+ if (hasElement) {
+ selection = this.list.getStructuredSelection();
+ final int selectionCount = selection.size();
+ if (selectionCount <= 0 || selectionCount > itemCount) {
+ selection = null;
+ }
+ } else {
+ selection = null;
+ }
+ this.removeButton.setEnabled(selection != null);
+ this.clearButton.setEnabled(hasElement);
+ if (this.isSortedElements) {
+ final Object firstElement = selection != null ? this.list.getTable().getItem(0).getData() : null;
+ final Object lastElement = selection != null ? this.list.getTable().getItem(this.list.getTable().getItemCount() - 1).getData() : null;
+ final boolean isNotFirst = firstElement != null && selection != null && firstElement != selection.getFirstElement();
+ final boolean isNotLast = lastElement != null && selection != null && lastElement != selection.getFirstElement();
+ this.moveTopButton.setEnabled(isNotFirst);
+ this.moveUpButton.setEnabled(isNotFirst);
+ this.moveDownButton.setEnabled(isNotLast);
+ this.moveBottomButton.setEnabled(isNotLast);
+ }
+ }
+
+ /**
+ * Sets the type conversions to be displayed in this block.
+ *
+ * @param typeConversions the type conversions.
+ * @param notifyController indicates if the controller should be notified.
+ */
+ protected void setTypeConversions(List> typeConversions, boolean notifyController) {
+ this.conversions.clear();
+ if (typeConversions != null) {
+ for (final Pair entry : typeConversions) {
+ this.conversions.add(new ConversionMapping(entry.getKey(), entry.getValue()));
+ }
+ }
+ this.list.setInput(this.conversions);
+ refreshListUI();
+ if (notifyController) {
+ preferenceValueChanged();
+ }
+ }
+
+ /** Add a type conversion.
+ *
+ * @param javaType the name of the java type.
+ * @param targetType the name of the target type.
+ * @param updateSelection indicates if the selection should be updated.
+ */
+ protected void addTypeConversion(String javaType, String targetType, boolean updateSelection) {
+ final ConversionMapping entry = new ConversionMapping(javaType, targetType);
+ this.conversions.add(entry);
+ //refresh from model
+ refreshListUI();
+ if (updateSelection) {
+ this.list.setSelection(new StructuredSelection(entry));
+ }
+ //ensure labels are updated
+ if (!this.list.isBusy()) {
+ this.list.refresh(true);
+ }
+ enableButtons();
+ preferenceValueChanged();
+ }
+
+ private void preferenceValueChanged() {
+ final String preferenceValue = ExtraLanguagePreferenceAccess.toConverterPreferenceValue(
+ new TypeConversionIterator());
+ getController().controlChanged(
+ getPreferenceKey(),
+ preferenceValue);
+ }
+
+ /** Remove the current type conversion.
+ */
+ @SuppressWarnings("unchecked")
+ protected void removeCurrentTypeConversion() {
+ final IStructuredSelection selection = this.list.getStructuredSelection();
+ final String[] types = new String[selection.size()];
+ final Iterator iter = selection.iterator();
+ int i = 0;
+ while (iter.hasNext()) {
+ types[i] = iter.next().getSource();
+ i++;
+ }
+ removeTypeConversions(types);
+ }
+
+ /** Move the selection at the top.
+ */
+ protected void moveSelectionTop() {
+ final IStructuredSelection selection = this.list.getStructuredSelection();
+ final int index = this.conversions.indexOf(selection.getFirstElement());
+ if (index > 0) {
+ final int endIndex = index + selection.size() - 1;
+ for (int i = 0; i < selection.size(); ++i) {
+ final ConversionMapping next = this.conversions.remove(endIndex);
+ this.conversions.addFirst(next);
+ }
+ refreshListUI();
+ this.list.refresh(true);
+ enableButtons();
+ preferenceValueChanged();
+ }
+ }
+
+ /** Move the selection up.
+ */
+ protected void moveSelectionUp() {
+ final IStructuredSelection selection = this.list.getStructuredSelection();
+ final int index = this.conversions.indexOf(selection.getFirstElement());
+ if (index > 0) {
+ final ConversionMapping previous = this.conversions.remove(index - 1);
+ this.conversions.add(index + selection.size() - 1, previous);
+ refreshListUI();
+ this.list.refresh(true);
+ enableButtons();
+ preferenceValueChanged();
+ }
+ }
+
+ /** Move the selection down.
+ */
+ protected void moveSelectionDown() {
+ final IStructuredSelection selection = this.list.getStructuredSelection();
+ final int index = this.conversions.indexOf(selection.getFirstElement());
+ if (index >= 0 && (index + selection.size()) < this.conversions.size()) {
+ final ConversionMapping next = this.conversions.remove(index + selection.size());
+ this.conversions.add(index, next);
+ refreshListUI();
+ this.list.refresh(true);
+ enableButtons();
+ preferenceValueChanged();
+ }
+ }
+
+ /** Move the selection at the bottom.
+ */
+ protected void moveSelectionBottom() {
+ final IStructuredSelection selection = this.list.getStructuredSelection();
+ final int index = this.conversions.indexOf(selection.getFirstElement());
+ if (index >= 0 && (index + selection.size()) < this.conversions.size()) {
+ for (int i = 0; i < selection.size(); ++i) {
+ final ConversionMapping previous = this.conversions.remove(index);
+ this.conversions.addLast(previous);
+ }
+ refreshListUI();
+ this.list.refresh(true);
+ enableButtons();
+ preferenceValueChanged();
+ }
+ }
+
+ /** Remove the given type conversions.
+ *
+ * @param types the type conversions to be removed.
+ */
+ protected void removeTypeConversions(String... types) {
+ for (final String type : types) {
+ final Iterator iterator = this.conversions.iterator();
+ while (iterator.hasNext()) {
+ final ConversionMapping pair = iterator.next();
+ if (Strings.equal(pair.getSource(), type)) {
+ iterator.remove();
+ break;
+ }
+ }
+ }
+ refreshListUI();
+ this.list.refresh(true);
+ enableButtons();
+ preferenceValueChanged();
+ }
+
+ /** Remove all the current type conversions.
+ */
+ protected void removeAllTypeConversions() {
+ this.conversions.clear();
+ refreshListUI();
+ this.list.refresh(true);
+ enableButtons();
+ preferenceValueChanged();
+ }
+
+ /** Refresh the UI list of type conversions.
+ */
+ protected void refreshListUI() {
+ final Display display = Display.getDefault();
+ if (display.getThread().equals(Thread.currentThread())) {
+ if (!this.list.isBusy()) {
+ this.list.refresh();
+ }
+ } else {
+ display.syncExec(new Runnable() {
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public void run() {
+ if (!AbstractConversionTable.this.list.isBusy()) {
+ AbstractConversionTable.this.list.refresh();
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Sorts the type conversions by java type.
+ */
+ private void sortBySourceColumn() {
+ this.list.setComparator(new ViewerComparator() {
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2) {
+ if (e1 != null && e2 != null) {
+ return e1.toString().compareToIgnoreCase(e2.toString());
+ }
+ return super.compare(viewer, e1, e2);
+ }
+
+ @Override
+ public boolean isSorterProperty(Object element, String property) {
+ return true;
+ }
+ });
+ this.sort = Column.SOURCE;
+ }
+
+ /**
+ * No Sorts the type conversions.
+ */
+ private void noSort() {
+ this.list.setComparator(null);
+ this.sort = null;
+ }
+
+ /**
+ * Sorts the type conversions by target type.
+ */
+ private void sortByTargetColumn() {
+ this.list.setComparator(new ViewerComparator() {
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2) {
+ if (e1 != null && e2 != null) {
+ return e1.toString().compareToIgnoreCase(e2.toString());
+ }
+ return super.compare(viewer, e1, e2);
+ }
+
+ @Override
+ public boolean isSorterProperty(Object element, String property) {
+ return true;
+ }
+ });
+ this.sort = Column.TARGET;
+ }
+
+ /** Replies the key to be used for saving the column widths into the dialog widths.
+ *
+ * @return the key.
+ */
+ protected abstract String getColumnWidthDialogSettingsKey();
+
+ /**
+ * Restores the column widths from dialog settings.
+ *
+ * @param settings - the settings to read.
+ */
+ private void restoreColumnWidths(IDialogSettings settings) {
+ final int columnCount = this.table.getColumnCount();
+ for (int i = 0; i < columnCount; i++) {
+ int width = -1;
+ try {
+ width = settings.getInt(getPluginID() + getColumnWidthDialogSettingsKey() + i);
+ } catch (NumberFormatException exception) {
+ //
+ }
+
+ if ((width <= 0) || (i == this.table.getColumnCount() - 1)) {
+ this.table.getColumn(i).pack();
+ } else {
+ this.table.getColumn(i).setWidth(width);
+ }
+ }
+ }
+
+ /** Replies the key to be used for saving the column sort critera into the dialog widths.
+ *
+ * @return the key.
+ */
+ protected abstract String getColumnSortCriteraDialogSettingsKey();
+
+ /**
+ * Restore table settings from the given dialog store using the
+ * given key.
+ *
+ * @param settings - dialog settings store
+ */
+ private void restoreColumnSettings(IDialogSettings settings) {
+ this.list.getTable().layout(true);
+ restoreColumnWidths(settings);
+ if (!this.isSortedElements) {
+ this.sort = Column.SOURCE;
+ try {
+ final String columnName = settings.get(getPluginID() + getColumnSortCriteraDialogSettingsKey());
+ if (!Strings.isEmpty(columnName)) {
+ this.sort = Column.valueOf(columnName);
+ if (this.sort == null) {
+ this.sort = Column.SOURCE;
+ }
+ }
+ } catch (Throwable exception) {
+ //
+ }
+ assert this.sort != null;
+ switch (this.sort) {
+ case SOURCE:
+ sortBySourceColumn();
+ break;
+ case TARGET:
+ sortByTargetColumn();
+ break;
+ default:
+ }
+ } else {
+ noSort();
+ }
+ }
+
+ /** Definition of the columns in the table of the type conversions.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+ private enum Column {
+
+ /** The source column.
+ */
+ SOURCE,
+
+ /** The target column.
+ */
+ TARGET;
+
+ }
+
+ /** Definition of the conversion mapping.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+ protected static class ConversionMapping implements Comparable {
+
+ private String from;
+
+ private String to;
+
+ /** Constructor.
+ *
+ * @param from the source of the mapping.
+ * @param to the target of the mapping.
+ */
+ public ConversionMapping(String from, String to) {
+ this.from = Strings.emptyIfNull(from);
+ this.to = Strings.emptyIfNull(to);
+ }
+
+ /** Replies the source of the mapping.
+ *
+ * @return the source.
+ */
+ public String getSource() {
+ return this.from;
+ }
+
+ /** Replies the target of the mapping.
+ *
+ * @return the target.
+ */
+ public String getTarget() {
+ return this.to;
+ }
+
+ /** Change the source of the mapping.
+ *
+ * @param from the source.
+ */
+ public void setSource(String from) {
+ this.from = Strings.emptyIfNull(from);
+ }
+
+ /** Change the target of the mapping.
+ *
+ * @param to the target.
+ */
+ public void setTarget(String to) {
+ this.to = Strings.emptyIfNull(to);
+ }
+
+ @Override
+ public String toString() {
+ return getSource() + "->" + getTarget(); //$NON-NLS-1$
+ }
+
+ @Override
+ public int compareTo(ConversionMapping mapping) {
+ if (mapping == null) {
+ return Integer.MAX_VALUE;
+ }
+ return getSource().compareTo(mapping.getSource());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof ConversionMapping) {
+ return ((ConversionMapping) obj).getSource().equals(getSource());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return getSource().hashCode();
+ }
+
+ }
+
+ /**
+ * Label provider for type conversion list.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+ protected static class LabelProvider extends BaseLabelProvider implements ITableLabelProvider {
+
+ private final Image image;
+
+ /** Construct the provider of labels.
+ *
+ * @param image the image of the target language.
+ */
+ LabelProvider(Image image) {
+ this.image = image;
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex) {
+ switch (columnIndex) {
+ case 0:
+ return JavaUI.getSharedImages().getImage(ISharedImages.IMG_OBJS_CLASS);
+ case 1:
+ return this.image;
+ default:
+ }
+ return null;
+ }
+
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ final ConversionMapping pair = (ConversionMapping) element;
+ if (columnIndex == 1) {
+ return pair.getTarget();
+ }
+ return pair.getSource();
+ }
+
+ }
+
+ /**
+ * Content provider to show a list of type conversions.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+ protected class ContentProvider implements IStructuredContentProvider {
+
+ /** Construct a provider of JREs' list.
+ */
+ ContentProvider() {
+ //
+ }
+
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public Object[] getElements(Object input) {
+ return AbstractConversionTable.this.conversions.toArray();
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ //
+ }
+
+ @Override
+ public void dispose() {
+ //
+ }
+
+ }
+
+ /**
+ * Cell modifier.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+ protected static class CellModifier implements ICellModifier {
+
+ private final WeakReference table;
+
+ private final String sourceColumnPropertyName;
+
+ private final String targetColumnPropertyName;
+
+ /** Constructor.
+ *
+ * @param parent the parent of this modifier.
+ * @param sourceColumnPropertyName the property name of the source column.
+ * @param targetColumnPropertyName the property name of the target column.
+ */
+ CellModifier(AbstractConversionTable parent, String sourceColumnPropertyName, String targetColumnPropertyName) {
+ this.table = new WeakReference<>(parent);
+ this.sourceColumnPropertyName = sourceColumnPropertyName;
+ this.targetColumnPropertyName = targetColumnPropertyName;
+ }
+
+ @Override
+ public boolean canModify(Object element, String property) {
+ return true;
+ }
+
+ @Override
+ public Object getValue(Object element, String property) {
+ final ConversionMapping pair = (ConversionMapping) element;
+ if (Strings.equal(this.targetColumnPropertyName, property)) {
+ return pair.getTarget();
+ }
+ if (Strings.equal(this.sourceColumnPropertyName, property)) {
+ return pair.getSource();
+ }
+ return createDefaultValue();
+ }
+
+ /** Create the default value that is used when the edited column is not supported.
+ *
+ * @return the default value.
+ */
+ @SuppressWarnings("static-method")
+ protected String createDefaultValue() {
+ return new String();
+ }
+
+ @Override
+ public void modify(Object element, String property, Object value) {
+ final TableItem item = (TableItem) element;
+ if (Strings.equal(this.targetColumnPropertyName, property)) {
+ ((ConversionMapping) item.getData()).setTarget(Objects.toString(value));
+ this.table.get().refreshListUI();
+ } else if (Strings.equal(this.sourceColumnPropertyName, property)) {
+ ((ConversionMapping) item.getData()).setSource(Objects.toString(value));
+ this.table.get().refreshListUI();
+ }
+ }
+
+ }
+
+ /** Iterator on type conversions.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+ private class TypeConversionIterator implements Iterator {
+
+ private final Iterator iterator;
+
+ private String value;
+
+ @SuppressWarnings("synthetic-access")
+ TypeConversionIterator() {
+ this.iterator = AbstractConversionTable.this.conversions.iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return this.value != null || this.iterator.hasNext();
+ }
+
+ @Override
+ public String next() {
+ if (this.value != null) {
+ final String next = this.value;
+ this.value = null;
+ return next;
+ }
+ final ConversionMapping mapping = this.iterator.next();
+ this.value = mapping.getTarget();
+ return mapping.getSource();
+ }
+
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/AbstractExtraControl.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/AbstractExtraControl.java
new file mode 100644
index 0000000000..6f5e5b00eb
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/AbstractExtraControl.java
@@ -0,0 +1,102 @@
+/*
+ * $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.ui.generator.extra.properties;
+
+import java.lang.ref.WeakReference;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.swt.graphics.Image;
+
+/** Abstract implementation for the control wrappers that may be automatically considered in the optiona dialog.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public abstract class AbstractExtraControl implements IExtraControl {
+
+ private final WeakReference controller;
+
+ private final String pluginID;
+
+ private final Image languageImage;
+
+ private final IPreferenceStore preferenceStore;
+
+ /** Constructor.
+ *
+ * @param controller the controller.
+ * @param pluginID the identifier of the plugin.
+ * @param languageImage for the target language (16x16).
+ * @param preferenceStore the preference store to be used.
+ */
+ public AbstractExtraControl(IExtraControlController controller, String pluginID, Image languageImage,
+ IPreferenceStore preferenceStore) {
+ this.controller = new WeakReference<>(controller);
+ this.pluginID = pluginID;
+ this.languageImage = languageImage;
+ this.preferenceStore = preferenceStore;
+ }
+
+ /** Replies the controller of this widget.
+ *
+ * @return the controller.
+ */
+ protected IExtraControlController getController() {
+ return this.controller.get();
+ }
+
+ /** Register the given key.
+ *
+ * @param key the key to be registrered.
+ */
+ protected void registerKey(String key) {
+ getController().registerKey(key);
+ }
+
+ /** Replies the image associated to the extra language.
+ *
+ * @return the image.
+ */
+ protected Image getLanguageImage() {
+ return this.languageImage;
+ }
+
+ /** Replies the identifier of the plugin.
+ *
+ * @return the identifier.
+ */
+ protected String getPluginID() {
+ return this.pluginID;
+ }
+
+ /** Replies the preference store.
+ *
+ * @return the preference store.
+ */
+ protected IPreferenceStore getPreferenceStore() {
+ return this.preferenceStore;
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/AbstractExtraLanguagePropertyPage.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/AbstractExtraLanguagePropertyPage.java
new file mode 100644
index 0000000000..09285c891d
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/AbstractExtraLanguagePropertyPage.java
@@ -0,0 +1,150 @@
+/*
+ * $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.ui.generator.extra.properties;
+
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.preference.IPreferencePageContainer;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
+import org.eclipse.xtext.Constants;
+import org.eclipse.xtext.ui.preferences.PropertyAndPreferencePage;
+
+/** Abstract property page for configuring an extra language generator.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public abstract class AbstractExtraLanguagePropertyPage extends PropertyAndPreferencePage {
+
+ private AbstractGeneratorConfigurationBlock builderConfigurationBlock;
+
+ private String languageName;
+
+ /** Set the language name.
+ *
+ * @param languageName the name.
+ */
+ @Inject
+ public void setLanguageName(@Named(Constants.LANGUAGE_NAME) String languageName) {
+ this.languageName = languageName;
+ }
+
+ /** Change the configuration block.
+ *
+ * @param block the block.
+ */
+ protected final void setInternalConfigurationBlock(AbstractGeneratorConfigurationBlock block) {
+ assert block != null;
+ this.builderConfigurationBlock = block;
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ final IWorkbenchPreferenceContainer container = (IWorkbenchPreferenceContainer) getContainer();
+ this.builderConfigurationBlock.setProject(getProject());
+ this.builderConfigurationBlock.setWorkbenchPreferenceContainer(container);
+ this.builderConfigurationBlock.setStatusChangeListener(getNewStatusChangedListener());
+ super.createControl(parent);
+ }
+
+ @Override
+ protected Control createPreferenceContent(Composite composite, IPreferencePageContainer preferencePageContainer) {
+ return this.builderConfigurationBlock.createContents(composite);
+ }
+
+ @Override
+ protected boolean hasProjectSpecificOptions(IProject project) {
+ return this.builderConfigurationBlock.hasProjectSpecificOptions(project);
+ }
+
+ /** Replies the identifier of the page for a extra language generator.
+ *
+ * @return the identifier.
+ */
+ protected abstract String getGeneratorPageID();
+
+ @Override
+ protected String getPreferencePageID() {
+ return this.languageName + ".compiler.extra." + getGeneratorPageID() + ".preferencePage"; //$NON-NLS-1$//$NON-NLS-2$
+ }
+
+ @Override
+ protected String getPropertyPageID() {
+ return this.languageName + ".compiler.extra." + getGeneratorPageID() + ".propertyPage"; //$NON-NLS-1$//$NON-NLS-2$
+ }
+
+ @Override
+ public void dispose() {
+ if (this.builderConfigurationBlock != null) {
+ this.builderConfigurationBlock.dispose();
+ }
+ super.dispose();
+ }
+
+ @Override
+ protected void enableProjectSpecificSettings(boolean useProjectSpecificSettings) {
+ super.enableProjectSpecificSettings(useProjectSpecificSettings);
+ if (this.builderConfigurationBlock != null) {
+ this.builderConfigurationBlock.useProjectSpecificSettings(useProjectSpecificSettings);
+ }
+ }
+
+ @Override
+ protected void performDefaults() {
+ super.performDefaults();
+ if (this.builderConfigurationBlock != null) {
+ this.builderConfigurationBlock.performDefaults();
+ }
+ }
+
+ @Override
+ public boolean performOk() {
+ if (this.builderConfigurationBlock != null) {
+ if (!this.builderConfigurationBlock.performOk()) {
+ return false;
+ }
+ }
+ return super.performOk();
+ }
+
+ @Override
+ public void performApply() {
+ if (this.builderConfigurationBlock != null) {
+ this.builderConfigurationBlock.performApply();
+ }
+ }
+
+ @Override
+ public void setElement(IAdaptable element) {
+ super.setElement(element);
+ // no description for property page
+ setDescription(null);
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/AbstractGeneratorConfigurationBlock.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/AbstractGeneratorConfigurationBlock.java
new file mode 100644
index 0000000000..457f10cadb
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/AbstractGeneratorConfigurationBlock.java
@@ -0,0 +1,719 @@
+/*
+ * $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.ui.generator.extra.properties;
+
+import java.util.List;
+import java.util.Set;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.internal.ui.SWTFactory;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.layout.PixelConverter;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.TableEditor;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Widget;
+import org.eclipse.ui.forms.widgets.ExpandableComposite;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.eclipse.xtext.builder.EclipseOutputConfigurationProvider;
+import org.eclipse.xtext.builder.preferences.BuilderPreferenceAccess;
+import org.eclipse.xtext.generator.OutputConfiguration;
+import org.eclipse.xtext.ui.preferences.OptionsConfigurationBlock;
+import org.eclipse.xtext.ui.preferences.ScrolledPageContent;
+
+import io.sarl.lang.generator.extra.ExtraLanguageOutputConfigurations;
+import io.sarl.lang.ui.generator.extra.preferences.ExtraLanguagePreferenceAccess;
+import io.sarl.lang.ui.internal.LangActivator;
+
+/** Abstract implementation for the configuration block dedicated to an extra language generator.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+@SuppressWarnings({"checkstyle:classdataabstractioncoupling", "checkstyle:classfanoutcomplexity"})
+public abstract class AbstractGeneratorConfigurationBlock extends OptionsConfigurationBlock implements IExtraControlController {
+
+ /** Section name.
+ */
+ public static final String SETTINGS_SECTION_NAME = "ExtraLanguageGeneratorConfigurationBlock"; //$NON-NLS-1$
+
+ /** Boolean values for preferences.
+ */
+ protected static final String[] BOOLEAN_VALUES = new String[] {IPreferenceStore.TRUE, IPreferenceStore.FALSE};
+
+ private static final String IMAGE = "icons/experimental.png"; //$NON-NLS-1$
+
+ private static final int HEIGHT = 20;
+
+ private static final int INDENT_AMOUNT = 32;
+
+ private final List extraControls = Lists.newArrayList();
+
+ private final List tableItems = Lists.newArrayList();
+
+ private final boolean isExperimental;
+
+ @Inject
+ private EclipseOutputConfigurationProvider configurationProvider;
+
+ @Inject
+ private ExtraLanguagePreferenceAccess preferenceStoreAccess;
+
+ private IPreferenceStore projectPreferenceStore;
+
+ private String propertyPrefix;
+
+ /** Constructor.
+ *
+ * @param isExperimental indicates if the block should display experimental elements.
+ */
+ public AbstractGeneratorConfigurationBlock(boolean isExperimental) {
+ this.isExperimental = isExperimental;
+ }
+
+ @Override
+ public final String getPropertyPrefix() {
+ if (this.propertyPrefix == null) {
+ this.propertyPrefix = ExtraLanguagePreferenceAccess.getPropertyPrefix(getPluginID());
+ }
+ return this.propertyPrefix;
+ }
+
+ /** Replies if the block should display experimental elements.
+ *
+ * @return {@code true} if the experimental elements should be shown.
+ */
+ public boolean isExperimental() {
+ return this.isExperimental;
+ }
+
+ /** Replies the preference access.
+ *
+ * @return the access.
+ */
+ public ExtraLanguagePreferenceAccess getPreferenceAccess() {
+ return this.preferenceStoreAccess;
+ }
+
+ @Override
+ public void setProject(IProject project) {
+ super.setProject(project);
+ setPreferenceStore(createPreferenceStoreInstance(project));
+ }
+
+ @Override
+ public void setPreferenceStore(IPreferenceStore preferenceStore) {
+ this.projectPreferenceStore = preferenceStore;
+ super.setPreferenceStore(preferenceStore);
+ }
+
+ /** Create the instance of the preference store.
+ *
+ * @param project the project.
+ * @return the preference store.
+ */
+ protected IPreferenceStore createPreferenceStoreInstance(IProject project) {
+ return this.preferenceStoreAccess.getWritablePreferenceStore(getProject());
+ }
+
+ /** Replies the project preference store.
+ *
+ * @return the preference store.
+ */
+ protected IPreferenceStore getPreferenceStore() {
+ if (this.projectPreferenceStore == null) {
+ this.projectPreferenceStore = createPreferenceStoreInstance(getProject());
+ }
+ return this.projectPreferenceStore;
+ }
+
+ /** Add an extra control in the block.
+ *
+ * @param control the control to add.
+ */
+ protected void addExtraControl(IExtraControl control) {
+ this.extraControls.add(control);
+ }
+
+ @Override
+ protected Control doCreateContents(Composite parent) {
+ final PixelConverter pixelConverter = new PixelConverter(parent);
+ setShell(parent.getShell());
+ final Composite mainComp = new Composite(parent, SWT.NONE);
+ mainComp.setFont(parent.getFont());
+ final GridLayout layout = new GridLayout();
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ mainComp.setLayout(layout);
+ final Composite othersComposite = createGeneratorContent(mainComp);
+ final GridData gridData = new GridData(GridData.FILL, GridData.FILL, true, true);
+ gridData.heightHint = pixelConverter.convertHeightInCharsToPixels(HEIGHT);
+ othersComposite.setLayoutData(gridData);
+ validateSettings(null, null, null);
+ return mainComp;
+ }
+
+ private Composite createGeneratorContent(Composite parent) {
+ final ScrolledPageContent pageContent = new ScrolledPageContent(parent);
+ final int columns = 3;
+ final GridLayout layout = new GridLayout();
+ layout.numColumns = columns;
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+
+ final Composite composite = pageContent.getBody();
+ composite.setLayout(layout);
+
+ if (isExperimental()) {
+ createExperimentalWarningMessage(composite);
+ }
+
+ ExpandableComposite excomposite = createStyleSection(composite, Messages.AbstractGeneratorConfigurationBlock_4, columns);
+ Composite othersComposite = new Composite(excomposite, SWT.NONE);
+ excomposite.setClient(othersComposite);
+ othersComposite.setLayout(new GridLayout(columns, false));
+ createGeneralSectionItems(othersComposite);
+
+ excomposite = createStyleSection(composite, Messages.AbstractGeneratorConfigurationBlock_6, columns);
+ othersComposite = new Composite(excomposite, SWT.NONE);
+ excomposite.setClient(othersComposite);
+ othersComposite.setLayout(new GridLayout(columns, false));
+ createOutputSectionItems(othersComposite, getOutputConfiguration());
+
+ excomposite = createStyleSection(composite, Messages.AbstractGeneratorConfigurationBlock_5, columns);
+ othersComposite = SWTFactory.createComposite(excomposite, parent.getFont(), 2, 1, GridData.FILL_BOTH);
+ excomposite.setClient(othersComposite);
+ createTypeConversionSectionItems(othersComposite);
+
+ excomposite = createStyleSection(composite, Messages.AbstractGeneratorConfigurationBlock_7, columns);
+ othersComposite = SWTFactory.createComposite(excomposite, parent.getFont(), 2, 1, GridData.FILL_BOTH);
+ excomposite.setClient(othersComposite);
+ createFeatureConversionSectionItems(othersComposite);
+
+ createAdditionalSections(composite);
+
+ registerKey(getIsProjectSpecificPropertyKey(getPropertyPrefix()));
+ IDialogSettings section = getDialogSettings().getSection(SETTINGS_SECTION_NAME);
+ if (section == null) {
+ section = getDialogSettings().addNewSection(SETTINGS_SECTION_NAME);
+ }
+ restoreSectionExpansionStates(section);
+ return pageContent;
+ }
+
+ /** Replies the output configuration associated to the extra language generator.
+ *
+ * @return the output configuration.
+ */
+ protected OutputConfiguration getOutputConfiguration() {
+ final Set outputConfigurations = this.configurationProvider.getOutputConfigurations(getProject());
+ final String expectedName = ExtraLanguageOutputConfigurations.createOutputConfigurationName(getPluginID());
+ return Iterables.find(outputConfigurations, (it) -> expectedName.equals(it.getName()));
+ }
+
+ /**
+ * Returns the dialog settings for this UI plug-in.
+ * The dialog settings is used to hold persistent state data for the various
+ * wizards and dialogs of this plug-in in the context of a workbench.
+ *
+ * @return the dialog settings
+ */
+ public abstract IDialogSettings getDialogSettings();
+
+ /** Replies the identifier of the plugin that is associated to this configuration block.
+ *
+ * @return the dialog settings
+ */
+ public abstract String getPluginID();
+
+ /** Add additional section in the dialog.
+ *
+ * @param composite the parent.
+ */
+ protected void createAdditionalSections(Composite composite) {
+ //
+ }
+
+ /** Replies the image that represents the target language.
+ *
+ * @return the target language's image.
+ */
+ public abstract Image getTargetLanguageImage();
+
+ /** Create the items for the "Type Conversion" section.
+ *
+ * @param parentComposite the parent.
+ */
+ protected void createTypeConversionSectionItems(Composite parentComposite) {
+ final TypeConversionTable typeConversionTable = new TypeConversionTable(
+ this, getPluginID(), getTargetLanguageImage(),
+ getPreferenceStore());
+ typeConversionTable.doCreate(parentComposite, getDialogSettings());
+ makeScrollableCompositeAware(typeConversionTable.getControl());
+ addExtraControl(typeConversionTable);
+ }
+
+ private static ScrolledPageContent getParentScrolledComposite(Control control) {
+ Control parent = control.getParent();
+ while (!(parent instanceof ScrolledPageContent) && parent != null) {
+ parent = parent.getParent();
+ }
+ if (parent instanceof ScrolledPageContent) {
+ return (ScrolledPageContent) parent;
+ }
+ return null;
+ }
+
+ /** Make the given control awaer of the scrolling events.
+ *
+ * @param control the control to adapt to.
+ */
+ protected static void makeScrollableCompositeAware(Control control) {
+ final ScrolledPageContent parentScrolledComposite = getParentScrolledComposite(control);
+ if (parentScrolledComposite != null) {
+ parentScrolledComposite.adaptChild(control);
+ }
+ }
+
+ /** Create the items for the "Feature Conversion" section.
+ *
+ * @param parentComposite the parent.
+ */
+ protected void createFeatureConversionSectionItems(Composite parentComposite) {
+ final FeatureNameConversionTable typeConversionTable = new FeatureNameConversionTable(
+ this, getPluginID(), getTargetLanguageImage(),
+ getPreferenceStore());
+ typeConversionTable.doCreate(parentComposite, getDialogSettings());
+ makeScrollableCompositeAware(typeConversionTable.getControl());
+ addExtraControl(typeConversionTable);
+ }
+
+ /** Replies the text for the "enabling/disabling" label.
+ *
+ * @return the text.
+ */
+ protected abstract String getActivationText();
+
+ /** Create the "experimental" warning message.
+ *
+ * @param composite the parent.
+ */
+ protected void createExperimentalWarningMessage(Composite composite) {
+ final Label dangerIcon = new Label(composite, SWT.WRAP);
+ dangerIcon.setImage(getImage(IMAGE));
+ final GridData labelLayoutData = new GridData();
+ labelLayoutData.horizontalIndent = 0;
+ dangerIcon.setLayoutData(labelLayoutData);
+ }
+
+ /** Replies the image.
+ *
+ * @param imagePath the image path.
+ * @return the image.
+ */
+ protected final Image getImage(String imagePath) {
+ final ImageDescriptor descriptor = getImageDescriptor(imagePath);
+ if (descriptor == null) {
+ return null;
+ }
+ return descriptor.createImage();
+ }
+
+ /** Replies the image descriptor.
+ *
+ * @param imagePath the image path.
+ * @return the image descriptor.
+ */
+ @SuppressWarnings("static-method")
+ protected ImageDescriptor getImageDescriptor(String imagePath) {
+ final LangActivator activator = LangActivator.getInstance();
+ final ImageRegistry registry = activator.getImageRegistry();
+ ImageDescriptor descriptor = registry.getDescriptor(imagePath);
+ if (descriptor == null) {
+ descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(activator.getBundle().getSymbolicName(), imagePath);
+ if (descriptor != null) {
+ registry.put(imagePath, descriptor);
+ }
+ }
+ return descriptor;
+ }
+
+ /** Create the items for the "General" section.
+ *
+ * @param composite the parent.
+ */
+ protected void createGeneralSectionItems(Composite composite) {
+ addCheckBox(composite, getActivationText(),
+ ExtraLanguagePreferenceAccess.getPrefixedKey(getPluginID(),
+ ExtraLanguagePreferenceAccess.ENABLED_PROPERTY),
+ BOOLEAN_VALUES, 0);
+ }
+
+ @Override
+ protected Job getBuildJob(IProject project) {
+ final Job buildJob = new OptionsConfigurationBlock.BuildJob(Messages.AbstractGeneratorConfigurationBlock_3, project);
+ buildJob.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().buildRule());
+ buildJob.setUser(true);
+ return buildJob;
+ }
+
+ @Override
+ protected String[] getFullBuildDialogStrings(boolean workspaceSettings) {
+ final String message;
+ if (workspaceSettings) {
+ message = Messages.AbstractGeneratorConfigurationBlock_1;
+ } else {
+ message = Messages.AbstractGeneratorConfigurationBlock_2;
+ }
+ return new String[] {Messages.AbstractGeneratorConfigurationBlock_0, message};
+ }
+
+ @Override
+ protected void validateSettings(String changedKey, String oldValue, String newValue) {
+ //
+ }
+
+ @Override
+ public void dispose() {
+ IDialogSettings section = getDialogSettings().getSection(SETTINGS_SECTION_NAME);
+ if (section == null) {
+ section = getDialogSettings().addNewSection(SETTINGS_SECTION_NAME);
+ }
+ storeSectionExpansionStates(section);
+ super.dispose();
+ }
+
+ @Override
+ public void controlChanged(Widget widget) {
+ // Change the visibility
+ super.controlChanged(widget);
+ }
+
+ @Override
+ public void controlChanged(String preferenceKey, String preferenceValue) {
+ final String oldValue = setValue(preferenceKey, preferenceValue);
+ validateSettings(preferenceKey, oldValue, preferenceValue);
+ }
+
+ @Override
+ public void textChanged(Text textControl) {
+ // Change the visibility
+ super.textChanged(textControl);
+ }
+
+ @Override
+ public String getValue(String key) {
+ // Change the visibility
+ return super.getValue(key);
+ }
+
+ @Override
+ public void registerKey(String key) {
+ // Change the visibility
+ super.registerKey(key);
+ }
+
+ @Override
+ public void performDefaults() {
+ super.performDefaults();
+ }
+
+ /** Create the items for the "Output" section.
+ *
+ * @param composite the parent.
+ * @param outputConfiguration the output configuration.
+ */
+ protected void createOutputSectionItems(Composite composite, OutputConfiguration outputConfiguration) {
+ final Text defaultDirectoryField = addTextField(composite,
+ org.eclipse.xtext.builder.preferences.Messages.OutputConfigurationPage_Directory,
+ BuilderPreferenceAccess.getKey(outputConfiguration,
+ EclipseOutputConfigurationProvider.OUTPUT_DIRECTORY), 0, 0);
+ addCheckBox(composite,
+ org.eclipse.xtext.builder.preferences.Messages.OutputConfigurationPage_CreateDirectory,
+ BuilderPreferenceAccess.getKey(outputConfiguration,
+ EclipseOutputConfigurationProvider.OUTPUT_CREATE_DIRECTORY), BOOLEAN_VALUES, 0);
+ addCheckBox(composite,
+ org.eclipse.xtext.builder.preferences.Messages.OutputConfigurationPage_OverrideExistingResources,
+ BuilderPreferenceAccess.getKey(outputConfiguration,
+ EclipseOutputConfigurationProvider.OUTPUT_OVERRIDE), BOOLEAN_VALUES, 0);
+ addCheckBox(composite,
+ org.eclipse.xtext.builder.preferences.Messages.OutputConfigurationPage_CreatesDerivedResources,
+ BuilderPreferenceAccess.getKey(outputConfiguration,
+ EclipseOutputConfigurationProvider.OUTPUT_DERIVED), BOOLEAN_VALUES, 0);
+ addCheckBox(composite,
+ org.eclipse.xtext.builder.preferences.Messages.OutputConfigurationPage_CleanupDerivedResources,
+ BuilderPreferenceAccess.getKey(outputConfiguration,
+ EclipseOutputConfigurationProvider.OUTPUT_CLEANUP_DERIVED), BOOLEAN_VALUES, 0);
+ addCheckBox(composite,
+ org.eclipse.xtext.builder.preferences.Messages.OutputConfigurationPage_CleanDirectory,
+ BuilderPreferenceAccess.getKey(outputConfiguration,
+ EclipseOutputConfigurationProvider.OUTPUT_CLEAN_DIRECTORY), BOOLEAN_VALUES, 0);
+ final Button installAsPrimaryButton = addCheckBox(composite,
+ org.eclipse.xtext.builder.preferences.Messages.BuilderConfigurationBlock_InstallDslAsPrimarySource,
+ BuilderPreferenceAccess.getKey(outputConfiguration,
+ EclipseOutputConfigurationProvider.INSTALL_DSL_AS_PRIMARY_SOURCE), BOOLEAN_VALUES, 0);
+ final Button hideLocalButton = addCheckBox(composite,
+ org.eclipse.xtext.builder.preferences.Messages.BuilderConfigurationBlock_hideSyntheticLocalVariables,
+ BuilderPreferenceAccess.getKey(outputConfiguration,
+ EclipseOutputConfigurationProvider.HIDE_LOCAL_SYNTHETIC_VARIABLES), BOOLEAN_VALUES, 0);
+ hideLocalButton.setEnabled(installAsPrimaryButton.getSelection());
+ installAsPrimaryButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent exception) {
+ hideLocalButton.setEnabled(installAsPrimaryButton.getSelection());
+ }
+ });
+ final GridData hideLocalButtonData = new GridData();
+ hideLocalButtonData.horizontalIndent = INDENT_AMOUNT;
+ hideLocalButton.setLayoutData(hideLocalButtonData);
+ addCheckBox(composite,
+ org.eclipse.xtext.builder.preferences.Messages.OutputConfigurationPage_KeepLocalHistory,
+ BuilderPreferenceAccess.getKey(outputConfiguration,
+ EclipseOutputConfigurationProvider.OUTPUT_KEEP_LOCAL_HISTORY), BOOLEAN_VALUES, 0);
+
+ if (getProject() != null && !outputConfiguration.getSourceFolders().isEmpty()) {
+ final Button outputPerSourceButton = addCheckBox(composite,
+ org.eclipse.xtext.builder.preferences.Messages.OutputConfigurationPage_UseOutputPerSourceFolder,
+ BuilderPreferenceAccess.getKey(outputConfiguration,
+ EclipseOutputConfigurationProvider.USE_OUTPUT_PER_SOURCE_FOLDER), BOOLEAN_VALUES, 0);
+ final Table table = createOutputFolderTable(composite, outputConfiguration, defaultDirectoryField);
+ table.setVisible(outputPerSourceButton.getSelection());
+ outputPerSourceButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent exception) {
+ table.setVisible(outputPerSourceButton.getSelection());
+ }
+ });
+ }
+ }
+
+ @SuppressWarnings("checkstyle:magicnumber")
+ private Table createOutputFolderTable(Composite othersComposite, OutputConfiguration outputConfiguration,
+ Text defaultDirectoryField) {
+ final Table table = new Table(othersComposite, SWT.BORDER | SWT.FULL_SELECTION);
+ new TableColumn(table, SWT.NONE).setText(
+ org.eclipse.xtext.builder.preferences.Messages.OutputConfigurationPage_IgnoreSourceFolder);
+ new TableColumn(table, SWT.NONE).setText(
+ org.eclipse.xtext.builder.preferences.Messages.OutputConfigurationPage_SourceFolder);
+ new TableColumn(table, SWT.NONE).setText(
+ org.eclipse.xtext.builder.preferences.Messages.OutputConfigurationPage_OutputDirectory);
+ table.getColumn(0).setWidth(75);
+ table.getColumn(1).setWidth(200);
+ table.getColumn(2).setWidth(200);
+ table.pack();
+ table.setHeaderVisible(true);
+ table.setLinesVisible(true);
+
+ for (final String source : outputConfiguration.getSourceFolders()) {
+ final String outputForSourceFolderKey = BuilderPreferenceAccess.getOutputForSourceFolderKey(outputConfiguration, source);
+ registerKey(outputForSourceFolderKey);
+ final String ignoreSourceFolderKey = BuilderPreferenceAccess.getIgnoreSourceFolderKey(outputConfiguration, source);
+ registerKey(ignoreSourceFolderKey);
+ final String defaultOutputDirectoryKey = BuilderPreferenceAccess.getKey(outputConfiguration,
+ EclipseOutputConfigurationProvider.OUTPUT_DIRECTORY);
+ final TableItemData data = new TableItemData(source, outputForSourceFolderKey, ignoreSourceFolderKey,
+ defaultOutputDirectoryKey);
+
+ final TableItem item = new TableItem(table, SWT.NONE, 0);
+ this.tableItems.add(item);
+ item.setData(data);
+ refreshItem(item);
+
+ final TableEditor directoryEditor = new TableEditor(table);
+ directoryEditor.grabHorizontal = true;
+ table.addSelectionListener(new SelectionAdapter() {
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public void widgetSelected(SelectionEvent exception) {
+ if (exception.item != item) {
+ return;
+ }
+ if (isIgnored(item)) {
+ return;
+ }
+ final Control oldDirectoryField = directoryEditor.getEditor();
+ if (oldDirectoryField != null) {
+ oldDirectoryField.dispose();
+ }
+
+ final Text directoryField = new Text(table, SWT.NONE);
+ directoryField.setText(getOutputDirectory(item));
+ directoryField.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent me) {
+ setValue(data.getOutputDirectoryKey(), directoryField.getText());
+ refreshItem(item);
+ }
+ });
+ directoryField.addFocusListener(new FocusAdapter() {
+ @Override
+ public void focusLost(FocusEvent exception) {
+ directoryField.dispose();
+ }
+ });
+ directoryField.selectAll();
+ directoryField.setFocus();
+ directoryEditor.setEditor(directoryField, item, 2);
+ }
+ });
+ final TableEditor ignoreEditor = new TableEditor(table);
+ ignoreEditor.grabHorizontal = true;
+ final Button ignoreField = new Button(table, SWT.CHECK);
+ ignoreEditor.setEditor(ignoreField, item, 0);
+ ignoreField.setSelection(isIgnored(item));
+ ignoreField.addSelectionListener(new SelectionAdapter() {
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public void widgetSelected(SelectionEvent exception) {
+ setValue(data.getIgnoreKey(),
+ String.valueOf(ignoreField.getSelection()));
+ refreshItem(item);
+ }
+ });
+ defaultDirectoryField.addModifyListener(new ModifyListener() {
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public void modifyText(ModifyEvent exception) {
+ refreshItem(item);
+ }
+ });
+ }
+ return table;
+ }
+
+ private void refreshItem(final TableItem item) {
+ final TableItemData data = (TableItemData) item.getData();
+ item.setText(1, data.getSourceFolder());
+ final String outputDirectory = getOutputDirectory(item);
+ if ("".equals(outputDirectory)) { //$NON-NLS-1$
+ item.setForeground(2, Display.getCurrent().getSystemColor(SWT.COLOR_GRAY));
+ item.setText(2, getValue(data.getDefaultOutputDirectoryKey()));
+ } else {
+ item.setForeground(2, null);
+ item.setText(2, outputDirectory);
+ }
+ if (isIgnored(item)) {
+ item.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY));
+ } else {
+ item.setForeground(null);
+ }
+ }
+
+ private String getOutputDirectory(TableItem item) {
+ final TableItemData data = (TableItemData) item.getData();
+ return getValue(data.getOutputDirectoryKey());
+ }
+
+ private boolean isIgnored(TableItem item) {
+ final TableItemData data = (TableItemData) item.getData();
+ return Boolean.parseBoolean(getValue(data.getIgnoreKey()));
+ }
+
+ @Override
+ protected void updateControls() {
+ super.updateControls();
+ for (final TableItem item : this.tableItems) {
+ refreshItem(item);
+ }
+ for (final IExtraControl control : this.extraControls) {
+ control.updateControls();
+ }
+ }
+
+ /** Internal data.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+ private static class TableItemData {
+ private String sourceFolder;
+
+ private String outputDirectoryKey;
+
+ private String ignoreKey;
+
+ private String defaultOutputDirectoryKey;
+
+ /** Constructor.
+ *
+ * @param sourceFolder the source folder.
+ * @param outputDirectoryKey the output folder key.
+ * @param ignoreKey the ignore flag key.
+ * @param defaultOutputDirectoryKey the default output key.
+ */
+ TableItemData(String sourceFolder, String outputDirectoryKey, String ignoreKey,
+ String defaultOutputDirectoryKey) {
+ this.sourceFolder = sourceFolder;
+ this.outputDirectoryKey = outputDirectoryKey;
+ this.ignoreKey = ignoreKey;
+ this.defaultOutputDirectoryKey = defaultOutputDirectoryKey;
+ }
+
+ public String getSourceFolder() {
+ return this.sourceFolder;
+ }
+
+ public String getOutputDirectoryKey() {
+ return this.outputDirectoryKey;
+ }
+
+ public String getIgnoreKey() {
+ return this.ignoreKey;
+ }
+
+ public String getDefaultOutputDirectoryKey() {
+ return this.defaultOutputDirectoryKey;
+ }
+
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/FeatureNameConversionTable.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/FeatureNameConversionTable.java
new file mode 100644
index 0000000000..77db10cfd5
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/FeatureNameConversionTable.java
@@ -0,0 +1,98 @@
+/*
+ * $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.ui.generator.extra.properties;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.swt.graphics.Image;
+
+import io.sarl.lang.ui.generator.extra.preferences.ExtraLanguagePreferenceAccess;
+
+/** Table for feature name conversion definition.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+@SuppressWarnings("checkstyle:classdataabstractioncoupling")
+public class FeatureNameConversionTable extends AbstractConversionTable {
+
+ private static final String FEATURE_NAME_CONVERTER_COLUMN_WIDTH_ID = ".featureNameConverterSection.columnWidth"; //$NON-NLS-1$
+
+ private static final String FEATURE_NAME_CONVERTER_SORT_COLUMN = ".featureNameConverterSection.sortColumn"; //$NON-NLS-1$
+
+ /** Constructor.
+ *
+ * @param controller the controller.
+ * @param pluginID the identifier of the plugin.
+ * @param languageImage for the target language (16x16).
+ * @param preferenceStore the preference store to be used.
+ */
+ FeatureNameConversionTable(IExtraControlController controller, String pluginID, Image languageImage,
+ IPreferenceStore preferenceStore) {
+ super(controller, pluginID, languageImage, preferenceStore, true);
+ }
+
+ @Override
+ protected String getSourceColumnLabel() {
+ return Messages.FeatureNameConversionTable_8;
+ }
+
+ @Override
+ protected String getTargetColumnLabel() {
+ return Messages.FeatureNameConversionTable_9;
+ }
+
+ @Override
+ protected CellEditor createSourceColumnEditor() {
+ return createTextCellEditor();
+ }
+
+ @Override
+ protected CellEditor createTargetColumnEditor() {
+ return createTextCellEditor();
+ }
+
+ @Override
+ protected String getPreferenceKey() {
+ return ExtraLanguagePreferenceAccess.getPrefixedKey(getPluginID(),
+ ExtraLanguagePreferenceAccess.FEATURE_NAME_CONVERSION_PROPERTY);
+ }
+
+ @Override
+ protected String getColumnWidthDialogSettingsKey() {
+ return FEATURE_NAME_CONVERTER_COLUMN_WIDTH_ID;
+ }
+
+ @Override
+ protected String getColumnSortCriteraDialogSettingsKey() {
+ return FEATURE_NAME_CONVERTER_SORT_COLUMN;
+ }
+
+ @Override
+ protected String getIntroductionLabel() {
+ return Messages.FeatureNameConversionTable_0;
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/IExtraControl.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/IExtraControl.java
new file mode 100644
index 0000000000..b1a07e6289
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/IExtraControl.java
@@ -0,0 +1,38 @@
+/*
+ * $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.ui.generator.extra.properties;
+
+/** Control wrapper that may be automatically considered in the optiona dialog.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public interface IExtraControl {
+
+ /** Update the controls.
+ */
+ void updateControls();
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/IExtraControlController.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/IExtraControlController.java
new file mode 100644
index 0000000000..01643b0f13
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/IExtraControlController.java
@@ -0,0 +1,69 @@
+/*
+ * $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.ui.generator.extra.properties;
+
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Widget;
+
+/** Control wrapper that may be automatically considered in the option dialog.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public interface IExtraControlController {
+
+ /** Get a preference value.
+ *
+ * @param key the preference key.
+ * @return the value.
+ */
+ String getValue(String key);
+
+ /** Notify the controller that a widget content changed.
+ *
+ * @param widget the changed widget.
+ */
+ void controlChanged(Widget widget);
+
+ /** Notify the controller that a preference has changed.
+ *
+ * @param preferenceKey the key of the preference.
+ * @param preferenceValue the new value for the preference entry.
+ */
+ void controlChanged(String preferenceKey, String preferenceValue);
+
+ /** Notify the controller that a text widget has changed.
+ *
+ * @param textControl the changed widget.
+ */
+ void textChanged(Text textControl);
+
+ /** Register the given preference key.
+ *
+ * @param key the key to be registered.
+ */
+ void registerKey(String key);
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/Messages.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/Messages.java
new file mode 100644
index 0000000000..290a64b4ee
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/Messages.java
@@ -0,0 +1,63 @@
+/*
+ * $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.ui.generator.extra.properties;
+
+import org.eclipse.osgi.util.NLS;
+
+/** Messages.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+@SuppressWarnings("all")
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
+ public static String AbstractConversionTable_0;
+ public static String AbstractConversionTable_1;
+ public static String AbstractConversionTable_2;
+ public static String AbstractConversionTable_3;
+ public static String AbstractConversionTable_4;
+ public static String AbstractConversionTable_5;
+ public static String AbstractConversionTable_6;
+ public static String AbstractGeneratorConfigurationBlock_0;
+ public static String AbstractGeneratorConfigurationBlock_1;
+ public static String AbstractGeneratorConfigurationBlock_2;
+ public static String AbstractGeneratorConfigurationBlock_3;
+ public static String AbstractGeneratorConfigurationBlock_4;
+ public static String AbstractGeneratorConfigurationBlock_5;
+ public static String AbstractGeneratorConfigurationBlock_6;
+ public static String AbstractGeneratorConfigurationBlock_7;
+ public static String TypeConversionTable_8;
+ public static String TypeConversionTable_9;
+ public static String FeatureNameConversionTable_0;
+ public static String FeatureNameConversionTable_8;
+ public static String FeatureNameConversionTable_9;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/TypeConversionTable.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/TypeConversionTable.java
new file mode 100644
index 0000000000..8e3872be6d
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/TypeConversionTable.java
@@ -0,0 +1,93 @@
+/*
+ * $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.ui.generator.extra.properties;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.swt.graphics.Image;
+
+import io.sarl.lang.ui.generator.extra.preferences.ExtraLanguagePreferenceAccess;
+
+/** Table for type conversion definition.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+@SuppressWarnings("checkstyle:classdataabstractioncoupling")
+public class TypeConversionTable extends AbstractConversionTable {
+
+ private static final String TYPE_CONVERTER_COLUMN_WIDTH_ID = ".typeConverterSection.columnWidth"; //$NON-NLS-1$
+
+ private static final String TYPE_CONVERTER_SORT_COLUMN = ".typeConverterSection.sortColumn"; //$NON-NLS-1$
+
+ /** Constructor.
+ *
+ * @param controller the controller.
+ * @param pluginID the identifier of the plugin.
+ * @param languageImage for the target language (16x16).
+ * @param preferenceStore the preference store to be used.
+ */
+ TypeConversionTable(IExtraControlController controller, String pluginID, Image languageImage,
+ IPreferenceStore preferenceStore) {
+ super(controller, pluginID, languageImage, preferenceStore, false);
+ }
+
+ @Override
+ protected String getSourceColumnLabel() {
+ return Messages.TypeConversionTable_8;
+ }
+
+ @Override
+ protected String getTargetColumnLabel() {
+ return Messages.TypeConversionTable_9;
+ }
+
+ @Override
+ protected CellEditor createSourceColumnEditor() {
+ return createClassCellEditor();
+ }
+
+ @Override
+ protected CellEditor createTargetColumnEditor() {
+ return createTextCellEditor();
+ }
+
+ @Override
+ protected String getPreferenceKey() {
+ return ExtraLanguagePreferenceAccess.getPrefixedKey(getPluginID(),
+ ExtraLanguagePreferenceAccess.TYPE_CONVERSION_PROPERTY);
+ }
+
+ @Override
+ protected String getColumnWidthDialogSettingsKey() {
+ return TYPE_CONVERTER_COLUMN_WIDTH_ID;
+ }
+
+ @Override
+ protected String getColumnSortCriteraDialogSettingsKey() {
+ return TYPE_CONVERTER_SORT_COLUMN;
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/messages.properties b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/messages.properties
new file mode 100644
index 0000000000..77aea59eef
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/generator/extra/properties/messages.properties
@@ -0,0 +1,32 @@
+AbstractGeneratorConfigurationBlock_0=Generation Settings Changed
+AbstractGeneratorConfigurationBlock_1=The generation settings have changed. A full rebuild is required for changes to take effect. Do the full build now?
+AbstractGeneratorConfigurationBlock_2=The generation settings have changed. A rebuild of the project is required for changes to take effect. Build the project now?
+AbstractGeneratorConfigurationBlock_3=Rebuilding
+AbstractGeneratorConfigurationBlock_4=General
+AbstractGeneratorConfigurationBlock_5=Type Conversion
+AbstractGeneratorConfigurationBlock_6=Output Configuration
+AbstractGeneratorConfigurationBlock_7=Feature Conversion
+AbstractConversionTable_0=Add
+AbstractConversionTable_1=Remove
+AbstractConversionTable_2=Clear
+AbstractConversionTable_3=Top
+AbstractConversionTable_3=
+AbstractConversionTable_4=Up
+AbstractConversionTable_4=
+AbstractConversionTable_5=Down
+AbstractConversionTable_5=
+AbstractConversionTable_6=Bottom
+AbstractConversionTable_6=
+TypeConversionTable_8=Java Type
+TypeConversionTable_9=Target Type
+FeatureNameConversionTable_0=Special characters into the Java feature column:\n\
+ - '*' means anything.\n\
+ - 'P/y', where P is the path of the expression receiver, and y is the identifier of the feature.\n\
+Special variables into the target feature column:\n\
+ - '$0' means the receiver of the feature;\n\
+ - '$n' are the arguments of the feature, where n>1.\n\
+ - '$*' are the list of all the arguments.\n\
+If the "Java feature" ends with "()" is a a feature call conversion; Otherwise, it is a declaration\n\
+conversion. If the "Target feature" has not special variable, it is a simple feature renaming.
+FeatureNameConversionTable_8=Java Feature
+FeatureNameConversionTable_9=Target Feature
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/hyperlinking/Messages.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/hyperlinking/Messages.java
index 07e350ed7a..5c561ba3cd 100644
--- a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/hyperlinking/Messages.java
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/hyperlinking/Messages.java
@@ -31,7 +31,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.lang.ui.hyperlinking.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
public static String SARLHyperLinkingLabelProvider_0;
static {
// initialize resource bundle
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/labeling/Messages.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/labeling/Messages.java
index e898e1c726..2b7bcba207 100644
--- a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/labeling/Messages.java
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/labeling/Messages.java
@@ -31,7 +31,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.lang.ui.labeling.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
public static String SARLLabelProvider_0;
public static String SARLLabelProvider_1;
public static String SARLLabelProvider_2;
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/outline/Messages.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/outline/Messages.java
index b29d6e2e15..2166ea900f 100644
--- a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/outline/Messages.java
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/outline/Messages.java
@@ -31,7 +31,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.lang.ui.outline.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
public static String SARLBehaviorUnitOutlineFilter_0;
public static String SARLFieldOutlineFilter_0;
public static String SARLOperationOutlineFilter_0;
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/preferences/Messages.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/preferences/Messages.java
index ca55b078d8..eb288adfed 100644
--- a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/preferences/Messages.java
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/preferences/Messages.java
@@ -31,7 +31,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.lang.ui.preferences.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/preferences/SARLBuilderConfigurationBlock.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/preferences/SARLBuilderConfigurationBlock.java
index a47581763b..b36fd69680 100644
--- a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/preferences/SARLBuilderConfigurationBlock.java
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/preferences/SARLBuilderConfigurationBlock.java
@@ -24,12 +24,21 @@
import static io.sarl.lang.ui.preferences.SARLBuilderPreferenceAccess.PREF_GENERATE_INLINE;
import static io.sarl.lang.ui.preferences.SARLBuilderPreferenceAccess.PREF_USE_EXPRESSION_INTERPRETER;
+import java.util.Set;
+
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import org.eclipse.core.resources.IProject;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
+import org.eclipse.xtext.builder.EclipseOutputConfigurationProvider;
+import org.eclipse.xtext.generator.OutputConfiguration;
import org.eclipse.xtext.xbase.ui.builder.XbaseBuilderConfigurationBlock;
+import io.sarl.lang.generator.extra.ExtraLanguageOutputConfigurations;
+
/** Preference page that permits to configure the SARL builder.
*
* This page extends the Xbase page.
@@ -41,6 +50,9 @@
*/
public class SARLBuilderConfigurationBlock extends XbaseBuilderConfigurationBlock {
+ @Inject
+ private EclipseOutputConfigurationProvider configurationProvider;
+
@Override
protected void createGeneralSectionItems(Composite composite) {
super.createGeneralSectionItems(composite);
@@ -60,4 +72,14 @@ public void widgetSelected(SelectionEvent event) {
});
}
+ /** Replies the output configurations for the given project.
+ *
+ * @param project the project.
+ * @return the output configurations associated to the given project.
+ */
+ protected Set getOutputConfigurations(IProject project) {
+ final Set original = this.configurationProvider.getOutputConfigurations(getProject());
+ return Sets.filter(original, (it) -> !ExtraLanguageOutputConfigurations.isExtraLanguageOutputConfiguration(it.getName()));
+ }
+
}
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/preferences/SARLPreferenceStoreInitializer.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/preferences/SARLPreferenceStoreInitializer.java
index 30aa663c33..076159b775 100644
--- a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/preferences/SARLPreferenceStoreInitializer.java
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/preferences/SARLPreferenceStoreInitializer.java
@@ -32,6 +32,8 @@
import org.eclipse.xtext.ui.editor.preferences.PreferenceConstants;
import org.eclipse.xtext.validation.ConfigurableIssueCodesProvider;
+import io.sarl.lang.ui.generator.extra.ExtensionPointExtraLanguagePreferenceInitializer;
+
/** Initialize the preference store with SARL specific information.
*
* @author $Author: sgalland$
@@ -47,6 +49,9 @@ public class SARLPreferenceStoreInitializer implements IPreferenceStoreInitializ
@Inject
private ConfigurableIssueCodesProvider issueCodes;
+ @Inject
+ private ExtensionPointExtraLanguagePreferenceInitializer extraLanguagePreferenceInitializer;
+
@Override
public void initialize(IPreferenceStoreAccess preferenceStoreAccess) {
this.preferenceStoreAccess = preferenceStoreAccess;
@@ -62,6 +67,8 @@ public void initialize(IPreferenceStoreAccess preferenceStoreAccess) {
PreferenceConstants.EDITOR_SUB_WORD_NAVIGATION,
preferenceStore.getBoolean(org.eclipse.jdt.ui.PreferenceConstants.EDITOR_SUB_WORD_NAVIGATION));
+ // Initialize the generators for the extra languages.
+ setupExtraLanguageGeneratorDefaults(preferenceStoreAccess);
}
private void setupIssueCodesDefaults(IPreferenceStoreAccess preferenceStoreAccess) {
@@ -71,6 +78,10 @@ private void setupIssueCodesDefaults(IPreferenceStoreAccess preferenceStoreAcces
}
}
+ private void setupExtraLanguageGeneratorDefaults(IPreferenceStoreAccess preferenceStoreAccess) {
+ this.extraLanguagePreferenceInitializer.initialize(preferenceStoreAccess);
+ }
+
@Override
public void propertyChange(PropertyChangeEvent event) {
if (this.preferenceStoreAccess == null) {
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/quickfix/acceptors/Messages.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/quickfix/acceptors/Messages.java
index 4bc0a38add..f98558e66d 100644
--- a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/quickfix/acceptors/Messages.java
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/quickfix/acceptors/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.lang.ui.quickfix.acceptors.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
public static String AddSuppressWarnings_0;
public static String AddSuppressWarnings_1;
public static String AddSuppressWarnings_2;
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/refactoring/rename/Messages.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/refactoring/rename/Messages.java
index 3c693b5f05..38884407b3 100644
--- a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/refactoring/rename/Messages.java
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/refactoring/rename/Messages.java
@@ -33,7 +33,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.lang.ui.refactoring.rename.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
public static String SARLJdtPackageRenameParticipant_0;
static {
// initialize resource bundle
diff --git a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/validation/Messages.java b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/validation/Messages.java
index 0948a19ffd..954f2778f4 100644
--- a/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/validation/Messages.java
+++ b/main/coreplugins/io.sarl.lang.ui/src/io/sarl/lang/ui/validation/Messages.java
@@ -31,7 +31,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.lang.ui.validation.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/main/coreplugins/io.sarl.lang/META-INF/MANIFEST.MF b/main/coreplugins/io.sarl.lang/META-INF/MANIFEST.MF
index 2ae7ffe8f1..3caa8047c1 100644
--- a/main/coreplugins/io.sarl.lang/META-INF/MANIFEST.MF
+++ b/main/coreplugins/io.sarl.lang/META-INF/MANIFEST.MF
@@ -34,6 +34,7 @@ Export-Package: io.sarl.lang,
io.sarl.lang.documentation,
io.sarl.lang.formatting2,
io.sarl.lang.generator,
+ io.sarl.lang.generator.extra,
io.sarl.lang.jvmmodel,
io.sarl.lang.parser,
io.sarl.lang.parser.antlr,
@@ -46,5 +47,6 @@ Export-Package: io.sarl.lang,
io.sarl.lang.services,
io.sarl.lang.typesystem,
io.sarl.lang.util,
- io.sarl.lang.validation
+ io.sarl.lang.validation,
+ io.sarl.lang.validation.extra
Import-Package: org.apache.log4j
diff --git a/main/coreplugins/io.sarl.lang/plugin.xml b/main/coreplugins/io.sarl.lang/plugin.xml
index 0596383cb6..4db73bb63e 100644
--- a/main/coreplugins/io.sarl.lang/plugin.xml
+++ b/main/coreplugins/io.sarl.lang/plugin.xml
@@ -11,7 +11,4 @@
-
-
-
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/SARLRuntimeModule.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/SARLRuntimeModule.java
index 63fcd759cd..bbc702ba3c 100644
--- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/SARLRuntimeModule.java
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/SARLRuntimeModule.java
@@ -27,9 +27,6 @@
import com.google.inject.Injector;
import com.google.inject.Provider;
import com.google.inject.name.Names;
-import org.eclipse.xtend.core.compiler.XtendGenerator;
-import org.eclipse.xtext.generator.IGenerator;
-import org.eclipse.xtext.generator.IGenerator2;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import org.eclipse.xtext.scoping.IScopeProvider;
import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider;
@@ -42,7 +39,6 @@
import io.sarl.lang.bugfixes.refused.bug623.Bug623SARLReentrantTypeResolver;
import io.sarl.lang.bugfixes.unpublished.bug356.Bug356ImportedNamespaceScopeProvider;
import io.sarl.lang.bugfixes.unpublished.bug356.Bug356QualifiedNameConverter;
-import io.sarl.lang.generator.extra.ExtraLanguageGenerator;
import io.sarl.lang.validation.ConfigurableIssueSeveritiesProvider;
import io.sarl.lang.validation.IConfigurableIssueSeveritiesProvider;
import io.sarl.lang.validation.SARLValidator;
@@ -101,9 +97,6 @@ public void configure(Binder binder) {
binder.bind(ConfigurableIssueSeveritiesProvider.class).toProvider(provider);
binder.bind(IssueSeveritiesProvider.class).toProvider(provider);
binder.bind(IConfigurableIssueSeveritiesProvider.class).toProvider(provider);
- // Configure the extra generator provider.
- binder.bind(IGenerator2.class).annotatedWith(Names.named(ExtraLanguageGenerator.MAIN_GENERATOR_NAME))
- .to(XtendGenerator.class);
}
@Override
@@ -117,20 +110,15 @@ public Class extends IQualifiedNameConverter> bindIQualifiedNameConverter() {
return Bug356QualifiedNameConverter.class;
}
- @Override
- @SingletonBinding(eager = true)
- public Class extends SARLValidator> bindSARLValidator() {
- return Bug621SARLValidator.class;
- }
-
@Override
public Class extends DefaultReentrantTypeResolver> bindDefaultReentrantTypeResolver() {
return Bug623SARLReentrantTypeResolver.class;
}
@Override
- public Class extends IGenerator> bindIGenerator() {
- return ExtraLanguageGenerator.class;
+ @SingletonBinding(eager = true)
+ public Class extends SARLValidator> bindSARLValidator() {
+ return Bug621SARLValidator.class;
}
}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/bugfixes/pending/bug621/Bug621SARLExtraLanguageValidator.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/bugfixes/pending/bug621/Bug621SARLExtraLanguageValidator.java
new file mode 100644
index 0000000000..51a502aafb
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/bugfixes/pending/bug621/Bug621SARLExtraLanguageValidator.java
@@ -0,0 +1,201 @@
+/*
+ * $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.bugfixes.pending.bug621;
+
+import static org.eclipse.xtend.core.validation.IssueCodes.CONFLICTING_DEFAULT_METHODS;
+import static org.eclipse.xtend.core.validation.IssueCodes.DUPLICATE_METHOD;
+
+import java.util.List;
+import java.util.Set;
+
+import javax.inject.Inject;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.xtend.core.xtend.XtendPackage;
+import org.eclipse.xtend.core.xtend.XtendTypeDeclaration;
+import org.eclipse.xtext.common.types.JvmDeclaredType;
+import org.eclipse.xtext.common.types.JvmGenericType;
+import org.eclipse.xtext.common.types.JvmType;
+import org.eclipse.xtext.common.types.JvmTypeReference;
+import org.eclipse.xtext.xbase.typesystem.override.ConflictingDefaultOperation;
+import org.eclipse.xtext.xbase.typesystem.override.IResolvedOperation;
+import org.eclipse.xtext.xbase.typesystem.override.ResolvedFeatures;
+import org.eclipse.xtext.xbase.typesystem.util.ContextualVisibilityHelper;
+import org.eclipse.xtext.xbase.typesystem.util.IVisibilityHelper;
+import org.eclipse.xtext.xbase.typesystem.util.RecursionGuard;
+
+import io.sarl.lang.validation.extra.ExtraLanguageSupportValidator;
+
+/**
+ * Fixing the SARL issue 621: Error on multiple function inheritance.
+ *
+ * Issue is due to Xtend issue 191 (https://github.com/eclipse/xtext-xtend/pull/191),
+ * and the associated PR 192 (https://github.com/eclipse/xtext-xtend/pull/192)
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @see "https://github.com/sarl/sarl/issues/621"
+ * @see "https://github.com/eclipse/xtext-xtend/pull/191"
+ * @see "https://github.com/eclipse/xtext-xtend/pull/192"
+ */
+@SuppressWarnings("all")
+public class Bug621SARLExtraLanguageValidator extends ExtraLanguageSupportValidator {
+
+ @Inject
+ private IVisibilityHelper visibilityHelper;
+
+ private boolean contributesToConflict(JvmGenericType rootType, ConflictingDefaultOperation conflictingDefaultOperation) {
+ Set involvedInterfaces = Sets.newHashSet();
+ involvedInterfaces.add(conflictingDefaultOperation.getDeclaration().getDeclaringType());
+ for (IResolvedOperation conflictingOperation : conflictingDefaultOperation.getConflictingOperations()) {
+ involvedInterfaces.add(conflictingOperation.getDeclaration().getDeclaringType());
+ }
+ RecursionGuard recursionGuard = new RecursionGuard();
+ if (rootType.isInterface()) {
+ int contributingCount = 0;
+ for (JvmTypeReference typeRef : rootType.getExtendedInterfaces()) {
+ JvmType rawType = typeRef.getType();
+ if (rawType instanceof JvmDeclaredType && contributesToConflict((JvmDeclaredType) rawType, involvedInterfaces, recursionGuard)) {
+ contributingCount++;
+ }
+ }
+ return contributingCount >= 2;
+ } else {
+ return contributesToConflict(rootType, involvedInterfaces, recursionGuard);
+ }
+ }
+
+ private boolean contributesToConflict(JvmDeclaredType type, Set involvedInterfaces,
+ RecursionGuard guard) {
+ if (!guard.tryNext(type)) {
+ return false;
+ }
+ if (involvedInterfaces.contains(type)) {
+ return true;
+ }
+ for (JvmTypeReference typeRef : type.getExtendedInterfaces()) {
+ JvmType rawType = typeRef.getType();
+ if (rawType instanceof JvmDeclaredType && contributesToConflict((JvmDeclaredType) rawType, involvedInterfaces, guard)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected void doCheckOverriddenMethods(XtendTypeDeclaration xtendType, JvmGenericType inferredType,
+ ResolvedFeatures resolvedFeatures, Set flaggedOperations) {
+ List operationsMissingImplementation = null;
+ boolean doCheckAbstract = !inferredType.isAbstract();
+ if (doCheckAbstract) {
+ operationsMissingImplementation = Lists.newArrayList();
+ }
+ IVisibilityHelper visibilityHelper = new ContextualVisibilityHelper(this.visibilityHelper, resolvedFeatures.getType());
+ boolean flaggedType = false;
+ for (IResolvedOperation operation : resolvedFeatures.getAllOperations()) {
+ JvmDeclaredType operationDeclaringType = operation.getDeclaration().getDeclaringType();
+ if (operationDeclaringType != inferredType) {
+ if (operationsMissingImplementation != null && operation.getDeclaration().isAbstract()) {
+ operationsMissingImplementation.add(operation);
+ }
+ if (visibilityHelper.isVisible(operation.getDeclaration())) {
+ String erasureSignature = operation.getResolvedErasureSignature();
+ List declaredOperationsWithSameErasure =
+ resolvedFeatures.getDeclaredOperations(erasureSignature);
+ for (IResolvedOperation localOperation: declaredOperationsWithSameErasure) {
+ if (!localOperation.isOverridingOrImplementing(operation.getDeclaration()).isOverridingOrImplementing()) {
+ EObject source = findPrimarySourceElement(localOperation);
+ if (flaggedOperations.add(source)) {
+ if (operation.getDeclaration().isStatic() && !localOperation.getDeclaration().isStatic()) {
+ error("The instance method "
+ + localOperation.getSimpleSignature()
+ + " cannot override the static method "
+ + operation.getSimpleSignature() + " of type "
+ + getDeclaratorName(operation.getDeclaration()) + ".",
+ source, nameFeature(source), DUPLICATE_METHOD);
+ } else {
+ error("Name clash: The method "
+ + localOperation.getSimpleSignature() + " of type "
+ + inferredType.getSimpleName()
+ + " has the same erasure as "
+ +
+ // use source with other operations parameters to avoid confusion
+ // due to name transformations in JVM model inference
+ operation.getSimpleSignature() + " of type "
+ + getDeclaratorName(operation.getDeclaration()) + " but does not override it.",
+ source, nameFeature(source), DUPLICATE_METHOD);
+ }
+ }
+ }
+ }
+ if (operation instanceof ConflictingDefaultOperation
+ && contributesToConflict(inferredType, (ConflictingDefaultOperation) operation)
+ && !flaggedType) {
+ IResolvedOperation conflictingOperation = ((ConflictingDefaultOperation) operation).getConflictingOperations().get(0);
+ // Include the declaring class in the issue code in order to give better quick fixes
+ String[] uris = new String[] {
+ getDeclaratorName(operation.getDeclaration()) + "|"
+ + EcoreUtil.getURI(operation.getDeclaration()).toString(),
+ getDeclaratorName(conflictingOperation.getDeclaration()) + "|"
+ + EcoreUtil.getURI(conflictingOperation.getDeclaration()).toString()
+ };
+ if (!operation.getDeclaration().isAbstract() && !operation.getDeclaration().isDefault()
+ && !conflictingOperation.getDeclaration().isAbstract() && !conflictingOperation.getDeclaration().isDefault()) {
+ error("The type " + inferredType.getSimpleName()
+ + " inherits multiple implementations of the method " + conflictingOperation.getSimpleSignature()
+ + " from " + getDeclaratorName(conflictingOperation.getDeclaration())
+ + " and " + getDeclaratorName(operation.getDeclaration()) + ".",
+ xtendType, XtendPackage.Literals.XTEND_TYPE_DECLARATION__NAME,
+ CONFLICTING_DEFAULT_METHODS, uris);
+ } else if (!operation.getDeclaration().isDefault() && !conflictingOperation.getDeclaration().isDefault()) {
+ // At least one of the operations is non-abstract
+ IResolvedOperation abstractOp, nonabstractOp;
+ if (operation.getDeclaration().isAbstract()) {
+ abstractOp = operation;
+ nonabstractOp = conflictingOperation;
+ } else {
+ abstractOp = conflictingOperation;
+ nonabstractOp = operation;
+ }
+ error("The non-abstract method " + nonabstractOp.getSimpleSignature()
+ + " inherited from " + getDeclaratorName(nonabstractOp.getDeclaration())
+ + " conflicts with the method " + abstractOp.getSimpleSignature()
+ + " inherited from " + getDeclaratorName(abstractOp.getDeclaration()) + ".",
+ xtendType, XtendPackage.Literals.XTEND_TYPE_DECLARATION__NAME,
+ CONFLICTING_DEFAULT_METHODS, uris);
+ }
+ flaggedType = true;
+ }
+ }
+ }
+ }
+ if (operationsMissingImplementation != null && !operationsMissingImplementation.isEmpty() && !flaggedType) {
+ reportMissingImplementations(xtendType, inferredType, operationsMissingImplementation);
+ }
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/compiler/batch/Messages.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/compiler/batch/Messages.java
index 216ccb7c3c..e46cbe8fa3 100644
--- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/compiler/batch/Messages.java
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/compiler/batch/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.lang.compiler.batch.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
public static String Main_0;
public static String Main_1;
public static String Main_10;
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/formatting2/Messages.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/formatting2/Messages.java
index 32b97c4b07..01f2f65edb 100644
--- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/formatting2/Messages.java
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/formatting2/Messages.java
@@ -33,7 +33,7 @@
@SuppressWarnings("all")
public final class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.lang.formatting2.messages";
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages";
static {
// initialize resource bundle
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/Messages.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/Messages.java
index 68b20517f1..e37dfb9cf6 100644
--- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/Messages.java
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/Messages.java
@@ -33,7 +33,7 @@
@SuppressWarnings("all")
public final class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.lang.generator.messages";
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages";
public static String GeneratorConfigProvider2_0;
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/AbstractExpressionGenerator.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/AbstractExpressionGenerator.java
new file mode 100644
index 0000000000..05fbb69b41
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/AbstractExpressionGenerator.java
@@ -0,0 +1,667 @@
+/*
+ * $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.generator.extra;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.xtext.common.types.JvmConstructor;
+import org.eclipse.xtext.common.types.JvmDeclaredType;
+import org.eclipse.xtext.common.types.JvmExecutable;
+import org.eclipse.xtext.common.types.JvmFeature;
+import org.eclipse.xtext.common.types.JvmIdentifiableElement;
+import org.eclipse.xtext.common.types.JvmMember;
+import org.eclipse.xtext.common.types.JvmOperation;
+import org.eclipse.xtext.common.types.JvmType;
+import org.eclipse.xtext.common.types.util.TypeReferences;
+import org.eclipse.xtext.naming.QualifiedName;
+import org.eclipse.xtext.resource.persistence.StorageAwareResource;
+import org.eclipse.xtext.util.PolymorphicDispatcher;
+import org.eclipse.xtext.xbase.XAbstractFeatureCall;
+import org.eclipse.xtext.xbase.XBinaryOperation;
+import org.eclipse.xtext.xbase.XBlockExpression;
+import org.eclipse.xtext.xbase.XConstructorCall;
+import org.eclipse.xtext.xbase.XExpression;
+import org.eclipse.xtext.xbase.XFeatureCall;
+import org.eclipse.xtext.xbase.XMemberFeatureCall;
+import org.eclipse.xtext.xbase.compiler.IAppendable;
+import org.eclipse.xtext.xbase.featurecalls.IdentifiableSimpleNameProvider;
+import org.eclipse.xtext.xbase.jvmmodel.ILogicalContainerProvider;
+import org.eclipse.xtext.xbase.lib.Functions.Function0;
+import org.eclipse.xtext.xbase.lib.Functions.Function1;
+import org.eclipse.xtext.xbase.scoping.featurecalls.OperatorMapping;
+import org.eclipse.xtext.xbase.typesystem.IBatchTypeResolver;
+import org.eclipse.xtext.xbase.typesystem.IResolvedTypes;
+import org.eclipse.xtext.xbase.typesystem.references.LightweightTypeReference;
+import org.eclipse.xtext.xbase.util.XExpressionHelper;
+
+import io.sarl.lang.generator.extra.ExtraLanguageFeatureNameConverter.ConversionResult;
+import io.sarl.lang.services.SARLGrammarKeywordAccess;
+
+/** Abstract Generator of XExpression.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public abstract class AbstractExpressionGenerator implements IExpressionGenerator {
+
+ private static final String TYPE_CONVERTER_INSTANCE = "typeConverterInstance"; //$NON-NLS-1$
+
+ private static final String FEATURE_NAME_CONVERTER_INSTANCE = "featureNameConverterInstance"; //$NON-NLS-1$
+
+ private final PolymorphicDispatcher generateDispatcher;
+
+ private OperatorMapping operatorMapping;
+
+ private TypeReferences typeReferences;
+
+ private SARLGrammarKeywordAccess keywords;
+
+ private XExpressionHelper expressionHelper;
+
+ private IdentifiableSimpleNameProvider featureNameProvider;
+
+ private ILogicalContainerProvider contextProvider;
+
+ private IBatchTypeResolver typeResolver;
+
+ private Injector injector;
+
+ /** Constructor.
+ */
+ public AbstractExpressionGenerator() {
+ this.generateDispatcher = new PolymorphicDispatcher<>(
+ "_generate", 3, 3, //$NON-NLS-1$
+ Collections.singletonList(this));
+ }
+
+ /** Change the injector.
+ *
+ * @param injector the injector.
+ */
+ @Inject
+ public void setInjector(Injector injector) {
+ this.injector = injector;
+ }
+
+ /** Change the type resolver for expressions.
+ *
+ * @param resolver the batch type resolver.
+ */
+ @Inject
+ public void setTypeResolver(IBatchTypeResolver resolver) {
+ this.typeResolver = resolver;
+ }
+
+ /** Replies the type resolver for expressions.
+ *
+ * @return the batch type resolver.
+ */
+ public IBatchTypeResolver getTypeResolver() {
+ return this.typeResolver;
+ }
+
+ /** Change the provider of the logical container.
+ *
+ * @param provider the logical container provider.
+ */
+ @Inject
+ public void setLogicalContainerProvider(ILogicalContainerProvider provider) {
+ this.contextProvider = provider;
+ }
+
+ /** Replies the provider of the logical container.
+ *
+ * @return the logical container provider.
+ */
+ public ILogicalContainerProvider getLogicalContainerProvider() {
+ return this.contextProvider;
+ }
+
+ /** Change the basic feature name provider.
+ *
+ * @param provider the feature name provider.
+ */
+ @Inject
+ public void setFeatureNameProvider(IdentifiableSimpleNameProvider provider) {
+ this.featureNameProvider = provider;
+ }
+
+ /** Replies the basic feature name provider.
+ *
+ * @return the feature name provider.
+ */
+ public IdentifiableSimpleNameProvider getFeatureNameProvider() {
+ return this.featureNameProvider;
+ }
+
+ /** Change the SARL keyword accessor.
+ *
+ * @param keywords the keyword accessor.
+ */
+ @Inject
+ public void setKeywordAccessor(SARLGrammarKeywordAccess keywords) {
+ this.keywords = keywords;
+ }
+
+ /** Replies the SARL keyword accessor.
+ *
+ * @return the keyword accessor.
+ */
+ public SARLGrammarKeywordAccess getKeywordAccessor() {
+ return this.keywords;
+ }
+
+ /** Change the expression helper.
+ *
+ * @param helper the expression helper.
+ */
+ @Inject
+ public void setExpressionHelper(XExpressionHelper helper) {
+ this.expressionHelper = helper;
+ }
+
+ /** Replies the expression helper.
+ *
+ * @return the expression helper.
+ */
+ public XExpressionHelper getExpressionHelper() {
+ return this.expressionHelper;
+ }
+
+ /** Change the type reference finder.
+ *
+ * @param finder the type reference finder.
+ */
+ @Inject
+ public void setTypeReferences(TypeReferences finder) {
+ this.typeReferences = finder;
+ }
+
+ /** Replies the type reference finder.
+ *
+ * @return the type reference finder.
+ */
+ public TypeReferences getTypeReferences() {
+ return this.typeReferences;
+ }
+
+ /** Change the mapping for the operators.
+ *
+ * @param mapping the mapping.
+ */
+ @Inject
+ public void setOperatorMapping(OperatorMapping mapping) {
+ this.operatorMapping = mapping;
+ }
+
+ /** Replies the mapping for the operators.
+ *
+ * @return the mapping.
+ */
+ public OperatorMapping getOperatorMapping() {
+ return this.operatorMapping;
+ }
+
+ /** Compute the expected type of the given expression.
+ *
+ * @param expr the expression.
+ * @return the expected type of the argument.
+ */
+ protected LightweightTypeReference getExpectedType(XExpression expr) {
+ final IResolvedTypes resolvedTypes = getTypeResolver().resolveTypes(expr);
+ final LightweightTypeReference actualType = resolvedTypes.getActualType(expr);
+ return actualType;
+ }
+
+ /** Replies the initializer for the type converter.
+ *
+ * @return the initializer
+ */
+ @SuppressWarnings("static-method")
+ protected IExtraLanguageConversionInitializer getTypeConverterInitializer() {
+ return null;
+ }
+
+ /** Replies the identifier of the generator's plugin.
+ *
+ * @return the plugin's identifier.
+ */
+ protected abstract String getGeneratorPluginID();
+
+ @Override
+ public ExtraLanguageTypeConverter getTypeConverter(IExtraLanguageGeneratorContext context) {
+ ExtraLanguageTypeConverter converter = context.getData(TYPE_CONVERTER_INSTANCE, ExtraLanguageTypeConverter.class);
+ if (converter == null) {
+ converter = createTypeConverterInstance(getTypeConverterInitializer(), getGeneratorPluginID(), context);
+ this.injector.injectMembers(converter);
+ context.setData(TYPE_CONVERTER_INSTANCE, converter);
+ }
+ return converter;
+ }
+
+ /** Create the instance of the type converter.
+ *
+ * @param initializer the converter initializer.
+ * @param pluginID the identifier of the generator's plugin.
+ * @param context the genetation context.
+ * @return the type converter.
+ */
+ @SuppressWarnings("static-method")
+ protected ExtraLanguageTypeConverter createTypeConverterInstance(
+ IExtraLanguageConversionInitializer initializer,
+ String pluginID,
+ IExtraLanguageGeneratorContext context) {
+ return new ExtraLanguageTypeConverter(initializer, pluginID, context);
+ }
+
+ /** Replies the initializer for the feature name converter.
+ *
+ * @return the initializer
+ */
+ @SuppressWarnings("static-method")
+ protected IExtraLanguageConversionInitializer getFeatureNameConverterInitializer() {
+ return null;
+ }
+
+ @Override
+ public ExtraLanguageFeatureNameConverter getFeatureNameConverter(IExtraLanguageGeneratorContext context) {
+ ExtraLanguageFeatureNameConverter converter = context.getData(FEATURE_NAME_CONVERTER_INSTANCE,
+ ExtraLanguageFeatureNameConverter.class);
+ if (converter == null) {
+ converter = createFeatureNameConverterInstance(getFeatureNameConverterInitializer(), getGeneratorPluginID(), context);
+ this.injector.injectMembers(converter);
+ context.setData(TYPE_CONVERTER_INSTANCE, converter);
+ }
+ return converter;
+ }
+
+ /** Create the instance of the feature name converter.
+ *
+ * @param initializer the converter initializer.
+ * @param pluginID the identifier of the generator's plugin.
+ * @param context the generation context.
+ * @return the feature name converter.
+ */
+ @SuppressWarnings("static-method")
+ protected ExtraLanguageFeatureNameConverter createFeatureNameConverterInstance(
+ IExtraLanguageConversionInitializer initializer,
+ String pluginID,
+ IExtraLanguageGeneratorContext context) {
+ return new ExtraLanguageFeatureNameConverter(initializer, pluginID, context);
+ }
+
+ @Override
+ public XExpression generate(XExpression expression, LightweightTypeReference expectedType, IAppendable output,
+ IExtraLanguageGeneratorContext context) {
+ final LightweightTypeReference old = context.setExpectedExpressionType(expectedType);
+ try {
+ before(expression, output, context);
+ return this.generateDispatcher.invoke(expression, output, context);
+ } finally {
+ after(expression, output, context);
+ context.setExpectedExpressionType(old);
+ }
+ }
+
+ /** Invoked before an expression is processed.
+ *
+ * @param expression the expression.
+ * @param output the output.
+ * @param context the context.
+ */
+ protected void before(XExpression expression, IAppendable output, IExtraLanguageGeneratorContext context) {
+ //
+ }
+
+ /** Invoked after an expression is processed.
+ *
+ * @param expression the expression.
+ * @param output the output.
+ * @param context the context.
+ */
+ protected void after(XExpression expression, IAppendable output, IExtraLanguageGeneratorContext context) {
+ //
+ }
+
+ /** Get the string representation of an operator.
+ *
+ * @param call the call to the operator feature.
+ * @return the string representation of the operator or {@code null} if not a valid operator.
+ */
+ protected String getOperatorSymbol(XAbstractFeatureCall call) {
+ if (call != null) {
+ final Resource res = call.eResource();
+ if (res instanceof StorageAwareResource) {
+ final boolean isLoadedFromStorage = ((StorageAwareResource) res).isLoadedFromStorage();
+ if (isLoadedFromStorage) {
+ final QualifiedName operator = getOperatorMapping().getOperator(
+ QualifiedName.create(call.getFeature().getSimpleName()));
+ return Objects.toString(operator);
+ }
+ }
+ return call.getConcreteSyntaxFeatureName();
+ }
+ return null;
+ }
+
+ /** Compute the simple name for the called feature.
+ *
+ * @param featureCall the feature call.
+ * @param keywords the keyword accessor.
+ * @param logicalContainerProvider the provider of logicial container.
+ * @param featureNameProvider the provider of feature name.
+ * @param nullKeyword the null-equivalent keyword.
+ * @param referenceNameLambda replies the reference name or {@code null} if none.
+ * @return the simple name.
+ */
+ public static String getCallSimpleName(XAbstractFeatureCall featureCall, SARLGrammarKeywordAccess keywords,
+ ILogicalContainerProvider logicalContainerProvider,
+ IdentifiableSimpleNameProvider featureNameProvider,
+ String nullKeyword,
+ Function1 referenceNameLambda) {
+ String name = null;
+ final JvmIdentifiableElement calledFeature = featureCall.getFeature();
+ if (calledFeature instanceof JvmConstructor) {
+ final JvmDeclaredType constructorContainer = ((JvmConstructor) calledFeature).getDeclaringType();
+ final JvmIdentifiableElement logicalContainer = logicalContainerProvider.getNearestLogicalContainer(featureCall);
+ final JvmDeclaredType contextType = ((JvmMember) logicalContainer).getDeclaringType();
+ if (contextType == constructorContainer) {
+ name = keywords.getThisKeyword();
+ } else {
+ name = keywords.getSuperKeyword();
+ }
+ } else if (calledFeature != null) {
+ final String referenceName = referenceNameLambda.apply(calledFeature);
+ if (referenceName != null) {
+ name = referenceName;
+ } else if (calledFeature instanceof JvmOperation) {
+ name = featureNameProvider.getSimpleName(calledFeature);
+ } else {
+ name = featureCall.getConcreteSyntaxFeatureName();
+ }
+ }
+ if (name == null) {
+ return nullKeyword;
+ }
+ return name;
+ }
+
+ /** Compute the list of object that serve as the receiver for the given call.
+ *
+ * @param call the feature call to analyze.
+ * @param output the objects that constitute the call's receiver.
+ * @param thisKeyword the "this" keyword.
+ * @param referenceNameDefinition replies the name of the expression, if defined.
+ * @return {@code true} if a receiver was found; otherwise {@code false}.
+ */
+ public static boolean buildCallReceiver(XAbstractFeatureCall call, Function0 thisKeyword,
+ Function1 referenceNameDefinition, List output) {
+ if (call.isStatic()) {
+ if (call instanceof XMemberFeatureCall) {
+ final XMemberFeatureCall memberFeatureCall = (XMemberFeatureCall) call;
+ if (memberFeatureCall.isStaticWithDeclaringType()) {
+ final XAbstractFeatureCall target = (XAbstractFeatureCall) memberFeatureCall.getMemberCallTarget();
+ final JvmType declaringType = (JvmType) target.getFeature();
+ output.add(declaringType);
+ return true;
+ }
+ }
+ output.add(((JvmFeature) call.getFeature()).getDeclaringType());
+ return true;
+ }
+ final XExpression receiver = call.getActualReceiver();
+ if (receiver == null) {
+ return false;
+ }
+ final XExpression implicit = call.getImplicitReceiver();
+ if (receiver == implicit) {
+ output.add(thisKeyword.apply());
+ } else {
+ output.add(receiver);
+ if (receiver instanceof XAbstractFeatureCall) {
+ // some local types have a reference name bound to the empty string
+ // which is the reason why we have to check for an empty string as a valid
+ // reference name here
+ // see AnonymousClassCompilerTest.testCapturedLocalVar_04
+ // if it turns out that we have to deal with generics there too, we may
+ // have to create a field in the synthesized local class with a unique
+ // name that points to 'this'
+ if (((XAbstractFeatureCall) receiver).getFeature() instanceof JvmType) {
+ final String referenceName = referenceNameDefinition.apply(receiver);
+ if (referenceName != null && referenceName.length() == 0) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /** A specific feature call generator.
+ *
+ * Thus generator should be overriden in order to provide specific language implementation.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ */
+ protected abstract class FeatureCallGenerator {
+
+ /** Generation context.
+ */
+ protected final IExtraLanguageGeneratorContext context;
+
+ /** Receiver of code.
+ */
+ protected final IAppendable codeReceiver;
+
+ private final Function0 thisKeyworkLambda = () -> getKeywordAccessor().getThisKeyword();
+
+ private final Function1 referenceNameLambda;
+
+ private final Function1 referenceNameLambda2;
+
+ /** Constructor.
+ *
+ * @param context the generation context.
+ * @param codeReceiver the receiver for the target language code.
+ */
+ protected FeatureCallGenerator(IExtraLanguageGeneratorContext context, IAppendable codeReceiver) {
+ this.context = context;
+ this.codeReceiver = codeReceiver;
+ this.referenceNameLambda = (expr) -> getReferenceName(expr);
+ this.referenceNameLambda2 = (expr) -> {
+ if (this.codeReceiver.hasName(expr)) {
+ return this.codeReceiver.getName(expr);
+ }
+ return null;
+ };
+ }
+
+ private XExpression normalizeBlockExpression(XExpression expr) {
+ if (expr instanceof XBlockExpression) {
+ final XBlockExpression block = (XBlockExpression) expr;
+ if (block.getExpressions().size() == 1) {
+ return normalizeBlockExpression(block.getExpressions().get(0));
+ }
+ }
+ return expr;
+ }
+
+ private List getActualArguments(XAbstractFeatureCall expr) {
+ final List actualArguments = expr.getActualArguments();
+ return Lists.transform(actualArguments, (it) -> normalizeBlockExpression(it));
+ }
+
+ private List getActualArguments(XConstructorCall expr) {
+ final List actualArguments = expr.getArguments();
+ return Lists.transform(actualArguments, (it) -> normalizeBlockExpression(it));
+ }
+
+ /** Generate a feature call.
+ *
+ * @param expr the call expression.
+ */
+ public void generate(XAbstractFeatureCall expr) {
+ if (expr.isTypeLiteral()) {
+ final JvmType type = (JvmType) expr.getFeature();
+ this.codeReceiver.append(type);
+ //} else if (getExpressionHelper().isShortCircuitOperation(expr)) {
+ // generateShortCircuitInvocation(expr);
+ } else {
+ if (expr instanceof XMemberFeatureCall && ((XMemberFeatureCall) expr).isNullSafe()) {
+ featureCalltoJavaExpression(expr, () -> expr);
+ } else {
+ featureCalltoJavaExpression(expr, null);
+ }
+ }
+ }
+
+ /** Generate a constructor call.
+ *
+ * @param expr the call expression.
+ */
+ public void generate(XConstructorCall expr) {
+ final List leftOperand = new ArrayList<>();
+ final List receiver = new ArrayList<>();
+ final JvmConstructor feature = expr.getConstructor();
+ final List args = getActualArguments(expr);
+ final JvmType type = expr.getConstructor().getDeclaringType();
+ internalAppendCall(feature, leftOperand, receiver, type.getSimpleName(), args, null);
+ }
+
+ private boolean needMultiAssignment(XAbstractFeatureCall expr) {
+ if (expr instanceof XBinaryOperation) {
+ final XBinaryOperation binaryOperation = (XBinaryOperation) expr;
+ return binaryOperation.isReassignFirstArgument();
+ }
+ return false;
+ }
+
+ private String getReferenceName(XExpression expr) {
+ if (this.codeReceiver.hasName(expr)) {
+ return this.codeReceiver.getName(expr);
+ }
+ if (expr instanceof XFeatureCall) {
+ final XFeatureCall featureCall = (XFeatureCall) expr;
+ if (this.codeReceiver.hasName(featureCall.getFeature())) {
+ return this.codeReceiver.getName(featureCall.getFeature());
+ }
+ }
+ return null;
+ }
+
+ private void buildLeftOperand(XAbstractFeatureCall expr, List output) {
+ final XBinaryOperation binaryOperation = (XBinaryOperation) expr;
+ final XAbstractFeatureCall leftOperand = (XAbstractFeatureCall) binaryOperation.getLeftOperand();
+ final JvmIdentifiableElement feature = leftOperand.getFeature();
+ if (this.codeReceiver.hasName(feature)) {
+ output.add(this.codeReceiver.getName(feature));
+ return;
+ }
+ buildCallReceiver(leftOperand, this.thisKeyworkLambda, this.referenceNameLambda, output);
+ output.add(feature.getSimpleName());
+ }
+
+ @SuppressWarnings("checkstyle:npathcomplexity")
+ private void featureCalltoJavaExpression(XAbstractFeatureCall call, Function0 beginOfBlock) {
+ final List leftOperand = new ArrayList<>();
+ if (needMultiAssignment(call)) {
+ buildLeftOperand(call, leftOperand);
+ }
+ final List receiver = new ArrayList<>();
+ buildCallReceiver(call, this.thisKeyworkLambda, this.referenceNameLambda, receiver);
+ final JvmIdentifiableElement feature = call.getFeature();
+ List args = null;
+ if (feature instanceof JvmExecutable) {
+ args = getActualArguments(call);
+ }
+ final String name = getCallSimpleName(
+ call,
+ getKeywordAccessor(),
+ getLogicalContainerProvider(),
+ getFeatureNameProvider(),
+ nullKeyword(),
+ this.referenceNameLambda2);
+ internalAppendCall(feature, leftOperand, receiver, name, args, beginOfBlock);
+ }
+
+ private void internalAppendCall(JvmIdentifiableElement calledFeature, List leftOperand,
+ List receiver, String name, List args,
+ Function0 beginOfBlock) {
+ final ExtraLanguageFeatureNameConverter converter = getFeatureNameConverter(this.context);
+ final ConversionResult result = converter.convertFeatureCall(name, calledFeature, leftOperand, receiver, args);
+ if (result != null) {
+ if (result.isFeatureRenaming()) {
+ appendCall(calledFeature, leftOperand, receiver, result.toString(), args, beginOfBlock);
+ } else {
+ for (final Object obj : result.toComplexConversion()) {
+ if (obj instanceof CharSequence) {
+ this.codeReceiver.append((CharSequence) obj);
+ } else if (obj instanceof JvmType) {
+ this.codeReceiver.append((JvmType) obj);
+ } else if (obj instanceof LightweightTypeReference) {
+ this.codeReceiver.append((LightweightTypeReference) obj);
+ } else if (obj instanceof XExpression) {
+ AbstractExpressionGenerator.this.generate(
+ (XExpression) obj, this.codeReceiver, this.context);
+ }
+ }
+ }
+ }
+ }
+
+ /** Invoked to generate a feature call.
+ *
+ * The given values to the arguments are already converter by the {@link ExtraLanguageFeatureNameConverter}.
+ *
+ * @param calledFeature the called feature.
+ * @param leftOperand the elements to put consider as left operand of an assignment.
+ * @param receiver the receiver of the call.
+ * @param name the name of the called feature.
+ * @param args the arguments.
+ * @param beginOfBlock the expression to be tested at beginning of the block. It should be a "if EXPR not not".
+ */
+ protected abstract void appendCall(JvmIdentifiableElement calledFeature, List leftOperand,
+ List receiver, String name, List args,
+ Function0 beginOfBlock);
+
+ /** Replies the null keyword.
+ *
+ * @return the keyword.
+ */
+ protected abstract String nullKeyword();
+
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/AbstractExtraGenerator.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/AbstractExtraGenerator.java
deleted file mode 100644
index f5fbc0bebd..0000000000
--- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/AbstractExtraGenerator.java
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * $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.generator.extra;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-import org.eclipse.emf.common.util.EList;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.resource.Resource;
-import org.eclipse.xtext.common.types.JvmIdentifiableElement;
-import org.eclipse.xtext.common.types.JvmType;
-import org.eclipse.xtext.generator.AbstractGenerator;
-import org.eclipse.xtext.generator.IFileSystemAccess2;
-import org.eclipse.xtext.generator.IGeneratorContext;
-import org.eclipse.xtext.util.CancelIndicator;
-import org.eclipse.xtext.util.PolymorphicDispatcher;
-import org.eclipse.xtext.util.Strings;
-import org.eclipse.xtext.xbase.compiler.AbstractStringBuilderBasedAppendable;
-import org.eclipse.xtext.xbase.compiler.IAppendable;
-
-/** Abstract implementation for the generator from SARL to an extra language.
- *
- * @author $Author: sgalland$
- * @version $FullVersion$
- * @mavengroupid $GroupId$
- * @mavenartifactid $ArtifactId$
- * @since 0.6
- */
-public abstract class AbstractExtraGenerator extends AbstractGenerator {
-
- private final PolymorphicDispatcher beforeDispatcher;
-
- private final PolymorphicDispatcher generateDispatcher;
-
- private final PolymorphicDispatcher generateDispatcher2;
-
- private final PolymorphicDispatcher afterDispatcher;
-
- /** Construct the generator.
- */
- public AbstractExtraGenerator() {
- this.beforeDispatcher = new PolymorphicDispatcher(
- "_before", 2, 2, //$NON-NLS-1$
- Collections.singletonList(this)) {
- @Override
- protected Void handleNoSuchMethod(Object... params) {
- return null;
- }
- };
- this.generateDispatcher = new PolymorphicDispatcher<>(
- "_generate", 2, 2, //$NON-NLS-1$
- Collections.singletonList(this));
- this.generateDispatcher2 = new PolymorphicDispatcher<>(
- "_generate", 3, 3, //$NON-NLS-1$
- Collections.singletonList(this));
- this.afterDispatcher = new PolymorphicDispatcher(
- "_after", 2, 2, //$NON-NLS-1$
- Collections.singletonList(this)) {
- @Override
- protected Void handleNoSuchMethod(Object... params) {
- return null;
- }
- };
- }
-
- @Override
- public void beforeGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) {
- final GeneratorContext generatorContext = createGeneratorContext(fsa, context);
- final EList contents = input.getContents();
- for (final EObject obj : contents) {
- if (canGenerateFor(obj)) {
- before(obj, generatorContext);
- }
- }
- }
-
- @Override
- public void doGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) {
- final GeneratorContext generatorContext = createGeneratorContext(fsa, context);
- final EList contents = input.getContents();
- for (final EObject obj : contents) {
- if (canGenerateFor(obj)) {
- generate(obj, generatorContext);
- }
- }
- }
-
- @Override
- public void afterGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) {
- final GeneratorContext generatorContext = createGeneratorContext(fsa, context);
- final EList contents = input.getContents();
- for (final EObject obj : contents) {
- if (canGenerateFor(obj)) {
- after(obj, generatorContext);
- }
- }
- }
-
- /** Create the generator context for this generator.
- *
- * @param fsa the file system access.
- * @param context the global context.
- * @return the context.
- */
- @SuppressWarnings("static-method")
- protected GeneratorContext createGeneratorContext(IFileSystemAccess2 fsa, IGeneratorContext context) {
- return new GeneratorContext(context, fsa);
- }
-
- /** Replies if this generator can generate resources from the given element.
- *
- * @param object the object for which the generation was queried.
- * @return {@code true} for generating the resources, {@code false} for ignoring the object.
- */
- @SuppressWarnings("static-method")
- protected boolean canGenerateFor(EObject object) {
- return !(object instanceof JvmIdentifiableElement);
- }
-
- /** Do something before the generation of the given object.
- *
- * @param object the object.
- * @param context the context.
- */
- protected void before(EObject object, GeneratorContext context) {
- this.beforeDispatcher.invoke(object, context);
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- */
- protected void generate(EObject object, GeneratorContext context) {
- this.generateDispatcher.invoke(object, context);
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param appendable the target for the generated content.
- */
- protected void generate(EObject object, GeneratorContext context, IAppendable appendable) {
- this.generateDispatcher2.invoke(object, context, appendable);
- }
-
- /** Do something after the generation of the given object.
- *
- * @param object the object.
- * @param context the context.
- */
- protected void after(EObject object, GeneratorContext context) {
- this.afterDispatcher.invoke(object, context);
- }
-
- /** The generator from SARL to the Python language.
- *
- * @author $Author: sgalland$
- * @version $FullVersion$
- * @mavengroupid $GroupId$
- * @mavenartifactid $ArtifactId$
- * @since 0.6
- */
- protected static class GeneratorContext implements IGeneratorContext {
-
- private final IGeneratorContext delegate;
-
- private IFileSystemAccess2 fileSystemAccess;
-
- private Map temporaryData;
-
- /** Create the context for the given delegate.
- *
- * @param delegate the delegate.
- * @param fileSystemAccess the file system access.
- */
- public GeneratorContext(IGeneratorContext delegate, IFileSystemAccess2 fileSystemAccess) {
- this.delegate = delegate;
- this.fileSystemAccess = fileSystemAccess;
- }
-
- @Override
- public CancelIndicator getCancelIndicator() {
- return this.delegate.getCancelIndicator();
- }
-
- /** Replies the delegate.
- *
- * @return the delegate.
- */
- public IGeneratorContext getDelegate() {
- return this.delegate;
- }
-
- /** Replies the file system access.
- *
- * @return the file system access.
- */
- public IFileSystemAccess2 getFileSystemAccess() {
- return this.fileSystemAccess;
- }
-
- /** Replies the stored data with the given identifier.
- * If the data was not found, the default value is replied.
- *
- * @param the type of the data.
- * @param id the identifier.
- * @param type the type of the data.
- * @param defaultValue the default value.
- * @return the data or the default value.
- */
- public T getData(String id, Class type, T defaultValue) {
- if (Strings.isEmpty(id) || this.temporaryData == null) {
- return defaultValue;
- }
- final Object data = this.temporaryData.get(id);
- try {
- return type.cast(data);
- } catch (Throwable exception) {
- return defaultValue;
- }
- }
-
- /** Replies the stored data with the given identifier.
- * If the data was not found, the default value is replied.
- *
- * @param the type of the data.
- * @param id the identifier.
- * @param type the type of the data.
- * @return the data or the default value.
- */
- public T getData(String id, Class type) {
- return getData(id, type);
- }
-
- /** Store data with the given identifier.
- *
- * @param id the identifier.
- * @param value the value.
- */
- public void setData(String id, Object value) {
- if (Strings.isEmpty(id)) {
- return;
- }
- if (value == null) {
- if (this.temporaryData != null) {
- this.temporaryData.remove(id);
- }
- return;
- }
- if (this.temporaryData != null) {
- this.temporaryData = new TreeMap<>();
- }
- this.temporaryData.put(id, value);
- }
-
- /** Clear all stored data.
- */
- public void clearData() {
- this.temporaryData = null;
- }
-
- }
-
- /** Appendable for extra languages.
- *
- * @author $Author: sgalland$
- * @version $FullVersion$
- * @mavengroupid $GroupId$
- * @mavenartifactid $ArtifactId$
- * @since 0.6
- */
- protected static class ExtraLanguageAppendable extends AbstractStringBuilderBasedAppendable {
-
- /** Constructor.
- */
- public ExtraLanguageAppendable() {
- super(false);
- }
-
- /** Constructor.
- *
- * @param indentation the indentation string.
- * @param lineSeparator the line separator string.
- */
- public ExtraLanguageAppendable(String indentation, String lineSeparator) {
- super(indentation, lineSeparator, false);
- }
-
- @Override
- protected void appendType(JvmType type, StringBuilder builder) {
- builder.append(type.getQualifiedName());
- }
-
- @Override
- protected void appendType(Class> type, StringBuilder builder) {
- builder.append(type.getName());
- }
-
- /** {@inheritDoc}.
- *
- * @deprecated No replacement.
- */
- @Override
- @Deprecated
- public List getImports() {
- return Collections.emptyList();
- }
-
- }
-
-}
-
-
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/AbstractExtraLanguageGenerator.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/AbstractExtraLanguageGenerator.java
new file mode 100644
index 0000000000..342866ebfc
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/AbstractExtraLanguageGenerator.java
@@ -0,0 +1,689 @@
+/*
+ * $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.generator.extra;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import com.google.inject.Injector;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.xtend.core.xtend.XtendMember;
+import org.eclipse.xtend.core.xtend.XtendTypeDeclaration;
+import org.eclipse.xtend2.lib.StringConcatenationClient;
+import org.eclipse.xtext.common.types.JvmConstructor;
+import org.eclipse.xtext.common.types.JvmIdentifiableElement;
+import org.eclipse.xtext.common.types.JvmMember;
+import org.eclipse.xtext.common.types.JvmTypeReference;
+import org.eclipse.xtext.common.types.util.TypeReferences;
+import org.eclipse.xtext.generator.AbstractGenerator;
+import org.eclipse.xtext.generator.IFileSystemAccess2;
+import org.eclipse.xtext.generator.IGeneratorContext;
+import org.eclipse.xtext.naming.IQualifiedNameConverter;
+import org.eclipse.xtext.naming.IQualifiedNameProvider;
+import org.eclipse.xtext.naming.QualifiedName;
+import org.eclipse.xtext.util.PolymorphicDispatcher;
+import org.eclipse.xtext.util.Strings;
+import org.eclipse.xtext.xbase.XExpression;
+import org.eclipse.xtext.xbase.compiler.ImportManager;
+import org.eclipse.xtext.xbase.compiler.output.ITreeAppendable;
+import org.eclipse.xtext.xbase.controlflow.IEarlyExitComputer;
+import org.eclipse.xtext.xbase.jvmmodel.JvmTypeExtensions;
+import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder;
+import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
+import org.eclipse.xtext.xbase.typesystem.IBatchTypeResolver;
+import org.eclipse.xtext.xbase.typesystem.IResolvedTypes;
+import org.eclipse.xtext.xbase.typesystem.references.LightweightTypeReference;
+
+import io.sarl.lang.actionprototype.IActionPrototypeProvider;
+import io.sarl.lang.jvmmodel.SarlJvmModelAssociations;
+import io.sarl.lang.sarl.SarlConstructor;
+import io.sarl.lang.sarl.SarlScript;
+
+/** Abstract implementation for the generator from SARL to an extra language.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public abstract class AbstractExtraLanguageGenerator extends AbstractGenerator implements IRootGenerator {
+
+ private static final String FILENAME_SEPARATOR = "/"; //$NON-NLS-1$
+
+ private final PolymorphicDispatcher beforeDispatcher;
+
+ private final PolymorphicDispatcher generateDispatcher;
+
+ private final PolymorphicDispatcher generateDispatcher2;
+
+ private final PolymorphicDispatcher afterDispatcher;
+
+ private IQualifiedNameProvider qualifiedNameProvider;
+
+ private IQualifiedNameConverter qualifiedNameConverter;
+
+ private JvmTypesBuilder jvmTypesBuilder;
+
+ private TypeReferences typeReferences;
+
+ private JvmTypeExtensions jvmTypeExtensions;
+
+ private IActionPrototypeProvider actionPrototypeProvider;
+
+ private SarlJvmModelAssociations sarlAssociations;
+
+ private IEarlyExitComputer earlyExitComputer;
+
+ private Injector injector;
+
+ private IBatchTypeResolver typeResolver;
+
+ /** Construct the generator.
+ */
+ public AbstractExtraLanguageGenerator() {
+ this.beforeDispatcher = new PolymorphicDispatcher(
+ "_before", 2, 2, //$NON-NLS-1$
+ Collections.singletonList(this)) {
+ @Override
+ protected Void handleNoSuchMethod(Object... params) {
+ return null;
+ }
+ };
+ this.generateDispatcher = new PolymorphicDispatcher<>(
+ "_generate", 2, 2, //$NON-NLS-1$
+ Collections.singletonList(this));
+ this.generateDispatcher2 = new PolymorphicDispatcher<>(
+ "_generate", 3, 3, //$NON-NLS-1$
+ Collections.singletonList(this));
+ this.afterDispatcher = new PolymorphicDispatcher(
+ "_after", 2, 2, //$NON-NLS-1$
+ Collections.singletonList(this)) {
+ @Override
+ protected Void handleNoSuchMethod(Object... params) {
+ return null;
+ }
+ };
+ }
+
+ /** Replies the type converter.
+ *
+ * @param context the context of the generation.
+ * @return the converter.
+ */
+ public ExtraLanguageTypeConverter getTypeConverter(IExtraLanguageGeneratorContext context) {
+ return getExpressionGenerator().getTypeConverter(context);
+ }
+
+ /** Replies the converter of feature names.
+ *
+ * @param context the context of the generation.
+ * @return the converter.
+ */
+ public ExtraLanguageFeatureNameConverter getFeatureNameConverter(IExtraLanguageGeneratorContext context) {
+ return getExpressionGenerator().getFeatureNameConverter(context);
+ }
+
+ /** Change the type reference finder.
+ *
+ * @param finder the type reference finder.
+ */
+ @Inject
+ public void setTypeReferences(TypeReferences finder) {
+ this.typeReferences = finder;
+ }
+
+ /** Replies the type reference finder.
+ *
+ * @return the type reference finder.
+ */
+ public TypeReferences getTypeReferences() {
+ return this.typeReferences;
+ }
+
+ /** Change the type resolver for expressions.
+ *
+ * @param resolver the batch type resolver.
+ */
+ @Inject
+ public void setTypeResolver(IBatchTypeResolver resolver) {
+ this.typeResolver = resolver;
+ }
+
+ /** Replies the type resolver for expressions.
+ *
+ * @return the batch type resolver.
+ */
+ public IBatchTypeResolver getTypeResolver() {
+ return this.typeResolver;
+ }
+
+ /** Change the injector.
+ *
+ * @param injector the injector.
+ */
+ @Inject
+ public void setInjector(Injector injector) {
+ this.injector = injector;
+ }
+
+ /** Replies the injector.
+ *
+ * @return the injector.
+ */
+ protected Injector getInjector() {
+ return this.injector;
+ }
+
+ /** Change the early exit computer.
+ *
+ * @param computer the early exit computer.
+ */
+ @Inject
+ public void setEarlyExitComputer(IEarlyExitComputer computer) {
+ this.earlyExitComputer = computer;
+ }
+
+ /** Replies the early exit computer.
+ *
+ * @return the early exit computer.
+ */
+ public IEarlyExitComputer getEarlyExitComputer() {
+ return this.earlyExitComputer;
+ }
+
+ /** Change the associations between the SARL elements and the JVM elements.
+ *
+ * @param associations the associations.
+ */
+ @Inject
+ public void setJvmModelAssociations(SarlJvmModelAssociations associations) {
+ this.sarlAssociations = associations;
+ }
+
+ /** Replies the associations between the SARL elements and the JVM elements.
+ *
+ * @return the associations.
+ */
+ public SarlJvmModelAssociations getJvmModelAssociations() {
+ return this.sarlAssociations;
+ }
+
+ /** Change the provider of action prototype.
+ *
+ * @param provider the action prototype provider.
+ */
+ @Inject
+ public void setLogicalContainerProvider(IActionPrototypeProvider provider) {
+ this.actionPrototypeProvider = provider;
+ }
+
+ /** Change the provider of action prototype.
+ *
+ * @param provider the action prototype provider.
+ */
+ @Inject
+ public void setActionPrototypeProvider(IActionPrototypeProvider provider) {
+ this.actionPrototypeProvider = provider;
+ }
+
+ /** Replies the provider of action prototype.
+ *
+ * @return the action prototype provider.
+ */
+ public IActionPrototypeProvider getActionPrototypeProvider() {
+ return this.actionPrototypeProvider;
+ }
+
+ /** Change the type builder.
+ *
+ * @param builder the builder.
+ */
+ @Inject
+ public void setTypeBuilder(JvmTypesBuilder builder) {
+ this.jvmTypesBuilder = builder;
+ }
+
+ /** Replies the type builder.
+ *
+ * @return the builder.
+ */
+ public JvmTypesBuilder getTypeBuilder() {
+ return this.jvmTypesBuilder;
+ }
+
+ /** Change the type extension provider.
+ *
+ * @param provider the type extension provider.
+ */
+ @Inject
+ public void setTypeExtensions(JvmTypeExtensions provider) {
+ this.jvmTypeExtensions = provider;
+ }
+
+ /** Replies the type extension provider.
+ *
+ * @return the type extension provider.
+ */
+ public JvmTypeExtensions getTypeExtensions() {
+ return this.jvmTypeExtensions;
+ }
+
+ /** Change the converter of qualified name.
+ *
+ * @param converter the converter.
+ */
+ @Inject
+ public void setQualifiedNameConverter(IQualifiedNameConverter converter) {
+ this.qualifiedNameConverter = converter;
+ }
+
+ /** Replies the converter of qualified name.
+ *
+ * @return the converer.
+ */
+ public IQualifiedNameConverter getQualifiedNameConverter() {
+ return this.qualifiedNameConverter;
+ }
+
+ /** Change the provider of qualified name.
+ *
+ * @param provider the provider.
+ */
+ @Inject
+ public void setQualifiedNameProvider(IQualifiedNameProvider provider) {
+ this.qualifiedNameProvider = provider;
+ }
+
+ /** Replies the provider of qualified name.
+ *
+ * @return the provider.
+ */
+ public IQualifiedNameProvider getQualifiedNameProvider() {
+ return this.qualifiedNameProvider;
+ }
+
+ /** Replies the expression associated to the given object.
+ * Usually, the expression is inside the given object.
+ *
+ * @param object the object.
+ * @return the expression, or {@code null} if none.
+ */
+ protected XExpression getAssociatedExpression(JvmMember object) {
+ final XExpression expr = getTypeBuilder().getExpression(object);
+ if (expr == null) {
+ // The member may be a automatically generated code with dynamic code-building strategies
+ final Procedure1 super ITreeAppendable> strategy = getTypeExtensions().getCompilationStrategy(object);
+ if (strategy != null) {
+ //
+ } else {
+ final StringConcatenationClient template = getTypeExtensions().getCompilationTemplate(object);
+ if (template != null) {
+ //
+ }
+ }
+ }
+ return expr;
+ }
+
+ /** Replies the generator dedicated to the expressions.
+ *
+ * @return the generator for expressions.
+ */
+ public abstract IExpressionGenerator getExpressionGenerator();
+
+ /** Replies the filename for the qualified name.
+ *
+ * @param name the qualified name.
+ * @param separator the filename separator.
+ * @return the filename.
+ */
+ protected String toFilename(QualifiedName name, String separator) {
+ final List segments = name.getSegments();
+ if (segments.isEmpty()) {
+ return ""; //$NON-NLS-1$
+ }
+ final StringBuilder builder = new StringBuilder();
+ builder.append(name.toString(separator));
+ builder.append(getFilenameExtension());
+ return builder.toString();
+ }
+
+ /** Replies the filename for the qualified name.
+ *
+ * @param name the qualified name.
+ * @return the filename.
+ */
+ protected String toFilename(QualifiedName name) {
+ return toFilename(name, FILENAME_SEPARATOR);
+ }
+
+ /** Replies the filename extension.
+ *
+ * @return the extension.
+ */
+ protected abstract String getFilenameExtension();
+
+ /** Replies the name of the output configuration to be used.
+ *
+ * @return the name of the output configuration.
+ */
+ protected abstract String getOutputConfigurationName();
+
+ /** Write the given file.
+ *
+ * @param name the name of the type to write.
+ * @param appendable the content to be written.
+ * @param context the generator context.
+ * @return {@code true} if the file was written.
+ */
+ protected boolean writeFile(QualifiedName name, ExtraLanguageAppendable appendable, IExtraLanguageGeneratorContext context) {
+ final ExtraLanguageAppendable fileAppendable = createAppendable(context);
+ generateFileHeader(name, fileAppendable, context);
+
+ final ImportManager importManager = appendable.getImportManager();
+ if (importManager != null && !importManager.getImports().isEmpty()) {
+ for (final String imported : importManager.getImports()) {
+ final QualifiedName qn = getQualifiedNameConverter().toQualifiedName(imported);
+ generateImportStatement(qn, fileAppendable, context);
+ }
+ fileAppendable.newLine();
+ }
+
+ fileAppendable.append(appendable.getContent());
+ final String content = fileAppendable.getContent();
+
+ if (!Strings.isEmpty(content)) {
+ final String fileName = toFilename(name, FILENAME_SEPARATOR);
+ final String outputConfiguration = getOutputConfigurationName();
+ if (Strings.isEmpty(outputConfiguration)) {
+ context.getFileSystemAccess().generateFile(fileName, content);
+ } else {
+ context.getFileSystemAccess().generateFile(fileName, outputConfiguration, content);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void beforeGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) {
+ final IExtraLanguageGeneratorContext generatorContext = createGeneratorContext(fsa, context, input);
+ final EList contents = input.getContents();
+ for (final EObject obj : contents) {
+ if (canGenerateFor(obj)) {
+ before(obj, generatorContext);
+ }
+ }
+ }
+
+ @Override
+ public void doGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) {
+ final IExtraLanguageGeneratorContext generatorContext = createGeneratorContext(fsa, context, input);
+ final EList contents = input.getContents();
+ for (final EObject obj : contents) {
+ if (canGenerateFor(obj)) {
+ generate(obj, generatorContext);
+ }
+ }
+ }
+
+ /** Generate the given object.
+ *
+ * This function calls the {@link #before(EObject, IExtraLanguageGeneratorContext)},
+ * {@link #generate(EObject, ExtraLanguageAppendable, IExtraLanguageGeneratorContext)}, and
+ * {@link #after(EObject, IExtraLanguageGeneratorContext)} functions.
+ *
+ * @param object the object.
+ * @param appendable the target for the generated content.
+ * @param context the context.
+ */
+ @Override
+ public void doGenerate(EObject object, ExtraLanguageAppendable appendable, IExtraLanguageGeneratorContext context) {
+ try {
+ before(object, context);
+ generate(object, appendable, context);
+ } finally {
+ after(object, context);
+ }
+ }
+
+ @Override
+ public void afterGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) {
+ final IExtraLanguageGeneratorContext generatorContext = createGeneratorContext(fsa, context, input);
+ final EList contents = input.getContents();
+ for (final EObject obj : contents) {
+ if (canGenerateFor(obj)) {
+ after(obj, generatorContext);
+ }
+ }
+ }
+
+ /** Create the generator context for this generator.
+ *
+ * @param fsa the file system access.
+ * @param context the global context.
+ * @param resource the resource.
+ * @return the context.
+ */
+ protected IExtraLanguageGeneratorContext createGeneratorContext(IFileSystemAccess2 fsa, IGeneratorContext context,
+ Resource resource) {
+ if (context instanceof IExtraLanguageGeneratorContext) {
+ return (IExtraLanguageGeneratorContext) context;
+ }
+ return new ExtraLanguageGeneratorContext(context, fsa, this, resource);
+ }
+
+ /** Replies the identifier of the plugin which defines the generator.
+ *
+ * @return the plugin identifier.
+ */
+ public abstract String getPluginID();
+
+ /** Create the appendable object.
+ *
+ * @param context the generation context.
+ * @return the appendable object.
+ */
+ protected abstract ExtraLanguageAppendable createAppendable(IExtraLanguageGeneratorContext context);
+
+ /** Replies if this generator can generate resources from the given element.
+ *
+ * @param object the object for which the generation was queried.
+ * @return {@code true} for generating the resources, {@code false} for ignoring the object.
+ */
+ @SuppressWarnings("static-method")
+ protected boolean canGenerateFor(EObject object) {
+ return !(object instanceof JvmIdentifiableElement);
+ }
+
+ /** Do something before the generation of the given object.
+ *
+ * @param object the object.
+ * @param context the context.
+ */
+ protected void before(EObject object, IExtraLanguageGeneratorContext context) {
+ this.beforeDispatcher.invoke(object, context);
+ }
+
+ /** Generate the given object.
+ *
+ * @param object the object.
+ * @param context the context.
+ */
+ protected void generate(EObject object, IExtraLanguageGeneratorContext context) {
+ this.generateDispatcher.invoke(object, context);
+ }
+
+ /** Generate the given object.
+ *
+ * @param object the object.
+ * @param appendable the target for the generated content.
+ * @param context the context.
+ */
+ protected void generate(EObject object, ExtraLanguageAppendable appendable, IExtraLanguageGeneratorContext context) {
+ this.generateDispatcher2.invoke(object, appendable, context);
+ }
+
+ /** Generate the given object.
+ *
+ * @param expression the expression to be generated.
+ * @param needReturn the type of the expression in the context of a returned expression from a function.
+ * @param appendable the target for the generated content.
+ * @param context the context.
+ */
+ protected void generate(XExpression expression, LightweightTypeReference needReturn, ExtraLanguageAppendable appendable,
+ IExtraLanguageGeneratorContext context) {
+ final IExpressionGenerator generator = getExpressionGenerator();
+ if (generator == null) {
+ throw new UnsupportedOperationException();
+ }
+ generator.generate(expression, needReturn, appendable, context);
+ }
+
+ /** Do something after the generation of the given object.
+ *
+ * @param object the object.
+ * @param context the context.
+ */
+ protected void after(EObject object, IExtraLanguageGeneratorContext context) {
+ this.afterDispatcher.invoke(object, context);
+ }
+
+ /** Generate the given script.
+ *
+ * @param script the script.
+ * @param context the context.
+ */
+ protected void _generate(SarlScript script, IExtraLanguageGeneratorContext context) {
+ if (script != null) {
+ for (final XtendTypeDeclaration content : script.getXtendTypes()) {
+ if (context.getCancelIndicator().isCanceled()) {
+ return;
+ }
+ try {
+ generate(content, context);
+ } finally {
+ context.clearData();
+ }
+ }
+ }
+ }
+
+ /** Generate the import for the given name.
+ *
+ * @param importedQualifiedName the imported name.
+ * @param appendable the appendable.
+ * @param context the context.
+ */
+ protected void generateImportStatement(QualifiedName importedQualifiedName, ExtraLanguageAppendable appendable,
+ IExtraLanguageGeneratorContext context) {
+ //
+ }
+
+ /** Generate the header of the file..
+ *
+ * @param qualifiedName the name of the type for which the file was created.
+ * @param appendable the appendable.
+ * @param context the context.
+ */
+ protected void generateFileHeader(QualifiedName qualifiedName, ExtraLanguageAppendable appendable,
+ IExtraLanguageGeneratorContext context) {
+ //
+ }
+
+ /** Generate the members (except constructors) for a Python class.
+ *
+ * @param members the members to be added.
+ * @param it the output.
+ * @param context the generation context.
+ * @return {@code true} if a member was generated. {@code false} if no member was generated.
+ */
+ protected boolean generateJvmMembers(List extends JvmMember> members, ExtraLanguageAppendable it,
+ IExtraLanguageGeneratorContext context) {
+ for (final JvmMember member : members) {
+ if (!(member instanceof JvmConstructor)) {
+ if (context.getCancelIndicator().isCanceled()) {
+ return false;
+ }
+ generate(member, it, context);
+ }
+ }
+ return true;
+ }
+
+ /** Generate the members (except constructors) for a Python class.
+ *
+ * @param members the members to be added.
+ * @param it the output.
+ * @param context the generation context.
+ * @return {@code true} if a member was generated. {@code false} if no member was generated.
+ */
+ protected boolean generateSarlMembers(List extends XtendMember> members, ExtraLanguageAppendable it,
+ IExtraLanguageGeneratorContext context) {
+ for (final XtendMember member : members) {
+ if (!(member instanceof SarlConstructor)) {
+ if (context.getCancelIndicator().isCanceled()) {
+ return false;
+ }
+ generate(member, it, context);
+ }
+ }
+ return true;
+ }
+
+ /** Replies the merged list with the extended and implemented types.
+ *
+ * @param extension the extended type.
+ * @param implemented the implemented types.
+ * @return the super types.
+ */
+ protected static List getSuperTypes(JvmTypeReference extension, List extends JvmTypeReference> implemented) {
+ final List list = new ArrayList<>();
+ if (extension != null) {
+ list.add(extension);
+ }
+ if (implemented != null) {
+ list.addAll(implemented);
+ }
+ return list;
+ }
+
+ /** Compute the expected type of the given expression.
+ *
+ * @param expr the expression.
+ * @return the expected type of the argument.
+ */
+ protected LightweightTypeReference getExpectedType(XExpression expr) {
+ final IResolvedTypes resolvedTypes = getTypeResolver().resolveTypes(expr);
+ final LightweightTypeReference actualType = resolvedTypes.getActualType(expr);
+ return actualType;
+ }
+
+}
+
+
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraGeneratorContext.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraGeneratorContext.java
deleted file mode 100644
index 6504db2c95..0000000000
--- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraGeneratorContext.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * $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.generator.extra;
-
-import org.eclipse.xtext.generator.IGenerator2;
-import org.eclipse.xtext.generator.IGeneratorContext;
-import org.eclipse.xtext.util.CancelIndicator;
-
-/** Context for the extra generator.
- *
- * @author $Author: sgalland$
- * @version $FullVersion$
- * @mavengroupid $GroupId$
- * @mavenartifactid $ArtifactId$
- * @since 0.6
- */
-public class ExtraGeneratorContext implements IGeneratorContext {
-
- private final IGeneratorContext delegate;
-
- private Iterable extraGenerators;
-
- /** Create the context for the given delegate.
- *
- * @param delegate the delegate.
- * @param extraGenerators the extra generators that could be used in this context.
- */
- public ExtraGeneratorContext(IGeneratorContext delegate, Iterable extraGenerators) {
- this.delegate = delegate;
- this.extraGenerators = extraGenerators;
- }
-
- @Override
- public CancelIndicator getCancelIndicator() {
- return this.delegate.getCancelIndicator();
- }
-
- /** Replies the delegate.
- *
- * @return the delegate.
- */
- public IGeneratorContext getDelegate() {
- return this.delegate;
- }
-
- /** Replies the extra generators.
- *
- * @return the extra generators.
- */
- public Iterable getExtraGenerators() {
- return this.extraGenerators;
- }
-
-}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageAppendable.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageAppendable.java
new file mode 100644
index 0000000000..5107829f4f
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageAppendable.java
@@ -0,0 +1,127 @@
+/*
+ * $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.generator.extra;
+
+import java.util.List;
+
+import org.eclipse.xtext.common.types.JvmType;
+import org.eclipse.xtext.xbase.compiler.AbstractStringBuilderBasedAppendable;
+import org.eclipse.xtext.xbase.compiler.ImportManager;
+
+/** Appendable for extra languages.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public class ExtraLanguageAppendable extends AbstractStringBuilderBasedAppendable {
+
+ private final ImportManager importManager;
+
+ /** Constructor.
+ */
+ public ExtraLanguageAppendable() {
+ this(null);
+ }
+
+ /** Constructor.
+ *
+ * @param indentation the indentation string.
+ * @param lineSeparator the line separator string.
+ */
+ public ExtraLanguageAppendable(String indentation, String lineSeparator) {
+ this(indentation, lineSeparator, null);
+ }
+
+ /** Constructor.
+ *
+ * @param importManager the import manager.
+ */
+ public ExtraLanguageAppendable(ImportManager importManager) {
+ super(false);
+ ImportManager im = importManager;
+ if (im == null) {
+ im = new ImportManager(true);
+ }
+ this.importManager = im;
+ }
+
+ /** Constructor.
+ *
+ * @param indentation the indentation string.
+ * @param lineSeparator the line separator string.
+ * @param importManager the import manager.
+ */
+ public ExtraLanguageAppendable(String indentation, String lineSeparator, ImportManager importManager) {
+ super(indentation, lineSeparator, false);
+ ImportManager im = importManager;
+ if (im == null) {
+ im = new ImportManager(true);
+ }
+ this.importManager = im;
+ }
+
+ /** Replies the line separator.
+ *
+ * @return the line separator.
+ */
+ @Override
+ public String getLineSeparator() {
+ // Change the visibility of the method.
+ return super.getLineSeparator();
+ }
+
+ @Override
+ protected void appendType(final JvmType type, StringBuilder builder) {
+ getImportManager().appendType(type, builder);
+ }
+
+ @Override
+ protected void appendType(final Class> type, StringBuilder builder) {
+ getImportManager().appendType(type, builder);
+ }
+
+ /** {@inheritDoc}
+ * @deprecated no replacement.
+ */
+ @Deprecated
+ @Override
+ public List getImports() {
+ return getImportManager().getImports();
+ }
+
+ /** Replies the import manager.
+ *
+ * @return the import manager.
+ */
+ public ImportManager getImportManager() {
+ return this.importManager;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString().trim();
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageFeatureNameConverter.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageFeatureNameConverter.java
new file mode 100644
index 0000000000..499f46f880
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageFeatureNameConverter.java
@@ -0,0 +1,708 @@
+/*
+ * $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.generator.extra;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.TreeMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.inject.Inject;
+
+import org.eclipse.xtext.common.types.JvmIdentifiableElement;
+import org.eclipse.xtext.common.types.JvmOperation;
+import org.eclipse.xtext.common.types.JvmType;
+import org.eclipse.xtext.util.Strings;
+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.featurecalls.IdentifiableSimpleNameProvider;
+import org.eclipse.xtext.xbase.jvmmodel.ILogicalContainerProvider;
+import org.eclipse.xtext.xbase.lib.Functions.Function0;
+import org.eclipse.xtext.xbase.lib.Functions.Function1;
+import org.eclipse.xtext.xbase.lib.Pair;
+import org.eclipse.xtext.xbase.typesystem.references.LightweightTypeReference;
+
+import io.sarl.lang.jvmmodel.SarlJvmModelAssociations;
+import io.sarl.lang.sarl.SarlAction;
+import io.sarl.lang.services.SARLGrammarKeywordAccess;
+
+/** Converter from Jvm feature name to the extra language feature name.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public class ExtraLanguageFeatureNameConverter {
+
+ private final IExtraLanguageConversionInitializer initializer;
+
+ private final IExtraLanguageGeneratorContext context;
+
+ private final String pluginID;
+
+ @Inject
+ private FeatureNameConverterRuleReader ruleReader;
+
+ @Inject
+ private SarlJvmModelAssociations associations;
+
+ @Inject
+ private SARLGrammarKeywordAccess keywords;
+
+ @Inject
+ private IdentifiableSimpleNameProvider simpleNameProvider;
+
+ @Inject
+ private ILogicalContainerProvider logicalContainerProvider;
+
+ private Map>> conversions;
+
+ private final Function0 thisKeyworkLambda = () -> this.keywords.getThisKeyword();
+
+ private final Function1 referenceNameLambda;
+
+ private final Function1 referenceNameLambda2;
+
+ /** Constructor.
+ *
+ * @param initializer the initializer.
+ * @param pluginID the identifier of the generator's plugin.
+ * @param context the generation context.
+ */
+ public ExtraLanguageFeatureNameConverter(IExtraLanguageConversionInitializer initializer, String pluginID,
+ IExtraLanguageGeneratorContext context) {
+ this.initializer = initializer;
+ this.context = context;
+ this.pluginID = pluginID;
+ this.referenceNameLambda = (expr) -> null;
+ this.referenceNameLambda2 = (expr) -> null;
+ }
+
+ /** Build the mapping table.
+ *
+ * @return the mapping table.
+ */
+ protected Map>> initMapping() {
+ final Map>> map = new TreeMap<>();
+ if (!this.ruleReader.initializeConversions(map, this.pluginID, this.context) && this.initializer != null) {
+ this.initializer.initializeConversions((simpleName, source, target) -> {
+ final char c = getKey(simpleName);
+ if (c == FeaturePattern.ALL_PATTERN_CHAR) {
+ for (int i = 'a'; i <= 'z'; ++i) {
+ createMappingEntry(map, (char) i, source, target);
+ }
+ } else {
+ createMappingEntry(map, c, source, target);
+ }
+ });
+ }
+ return map;
+ }
+
+ private static void createMappingEntry(Map>> map, char character,
+ String source, String target) {
+ List> internalStruct = map.get(character);
+ if (internalStruct == null) {
+ internalStruct = new ArrayList<>();
+ map.put(character, internalStruct);
+ }
+ internalStruct.add(new Pair<>(new FeaturePattern(source), new FeatureReplacement(target)));
+ }
+
+ /** Compute the mapping key for the given simple name.
+ *
+ * @param name the simple name.
+ * @return the mapping ket for the simple name.
+ */
+ public static char getKey(String name) {
+ return Character.toLowerCase(name.charAt(0));
+ }
+
+ /** Replies the type mapping.
+ *
+ * @return unmodifiable map of the type mapping.
+ */
+ public Map>> getMapping() {
+ if (this.conversions == null) {
+ this.conversions = initMapping();
+ }
+ return Collections.unmodifiableMap(this.conversions);
+ }
+
+ /** Replies the type of conversion for the given feature call.
+ *
+ * @param featureCall the feature call.
+ * @return the type of conversion.
+ */
+ public ConversionType getConversionTypeFor(XAbstractFeatureCall featureCall) {
+ if (this.conversions == null) {
+ this.conversions = initMapping();
+ }
+ final List receiver = new ArrayList<>();
+ AbstractExpressionGenerator.buildCallReceiver(
+ featureCall,
+ this.thisKeyworkLambda,
+ this.referenceNameLambda,
+ receiver);
+ final String simpleName = AbstractExpressionGenerator.getCallSimpleName(
+ featureCall,
+ this.keywords,
+ this.logicalContainerProvider,
+ this.simpleNameProvider,
+ this.keywords.getNullKeyword(),
+ this.referenceNameLambda2);
+ final List> struct = this.conversions.get(getKey(simpleName));
+ if (struct != null) {
+ final FeatureReplacement replacement = matchFirstPattern(struct, featureCall.getFeature().getIdentifier(), receiver);
+ if (replacement != null) {
+ return ConversionType.EXPLICIT;
+ }
+ return ConversionType.FORBIDDEN_CONVERSION;
+ }
+ return ConversionType.IMPLICIT;
+ }
+
+ /** Convert a full call to a feature.
+ *
+ * This function is supposed to change the two list parameters for reflecting the conversion.
+ *
+ * @param simpleName the simple name of the feature to be called.
+ * @param calledFeature the called feature.
+ * @param leftOperand the description of the elements into the left operand (usually, before assignment sign).
+ * @param receiver the description of the receiver, i.e. the object on which the feature is called.
+ * @param arguments the list of the arguments.
+ * @return a description of the conversion; or {@code null} for ignoring the call.
+ */
+ public ConversionResult convertFeatureCall(String simpleName, JvmIdentifiableElement calledFeature, List leftOperand,
+ List receiver, List arguments) {
+ if (this.conversions == null) {
+ this.conversions = initMapping();
+ }
+ final List> struct = this.conversions.get(getKey(simpleName));
+ if (struct != null) {
+ final FeatureReplacement replacement = matchFirstPattern(struct, calledFeature.getIdentifier(), receiver);
+ if (replacement != null) {
+ if (replacement.hasReplacement()) {
+ return replacement.replace(calledFeature, leftOperand, receiver, arguments);
+ }
+ return null;
+ }
+ }
+ return new ConversionResult(simpleName);
+ }
+
+ private static void loopReceiver(LinkedList sourceFeature, Object obj) {
+ if (obj instanceof XMemberFeatureCall) {
+ final XMemberFeatureCall memberFeatureCall = (XMemberFeatureCall) obj;
+ sourceFeature.addFirst(memberFeatureCall.getFeature().getSimpleName());
+ loopReceiver(sourceFeature, memberFeatureCall.getMemberCallTarget());
+ } else if (obj instanceof XFeatureCall) {
+ final XFeatureCall featureCall = (XFeatureCall) obj;
+ sourceFeature.addFirst(featureCall.getFeature().getIdentifier());
+ }
+ }
+
+ private static FeatureReplacement matchFirstPattern(List> patterns,
+ String source, List receiver) {
+ final LinkedList sourceFeature = new LinkedList<>();
+ for (final Object obj : receiver) {
+ loopReceiver(sourceFeature, obj);
+ }
+ sourceFeature.add(source);
+ for (final Pair patternMatching : patterns) {
+ final FeaturePattern pattern = patternMatching.getKey();
+ if (!pattern.isNameReplacement() && pattern.matches(sourceFeature)) {
+ return patternMatching.getValue();
+ }
+ }
+ return null;
+ }
+
+ private static FeatureReplacement matchFirstPattern(List> patterns, String source) {
+ final LinkedList sourceFeature = new LinkedList<>();
+ sourceFeature.add(source);
+ for (final Pair patternMatching : patterns) {
+ final FeaturePattern pattern = patternMatching.getKey();
+ if (pattern.isNameReplacement() && pattern.matches(sourceFeature)) {
+ return patternMatching.getValue();
+ }
+ }
+ return null;
+ }
+
+ /** Convert the given name for the given feature to its equivalent in the extra language.
+ *
+ * Usually, this function is called to convert the function's name when it is declared.
+ *
+ * @param simpleName the feature's simple name to convert.
+ * @param feature the JVM feature that corresponds to the name.
+ * @return the conversion result, or {@code null} if the equivalent function not exists,
+ * or {@code simpleName} if the function name should stay unchanged.
+ */
+ public String convertDeclarationName(String simpleName, SarlAction feature) {
+ assert simpleName != null;
+ assert feature != null;
+ final JvmOperation operation = this.associations.getDirectlyInferredOperation(feature);
+ if (operation != null) {
+ if (this.conversions == null) {
+ this.conversions = initMapping();
+ }
+ final List> struct = this.conversions.get(getKey(simpleName));
+ if (struct == null) {
+ return simpleName;
+ }
+ final FeatureReplacement replacement = matchFirstPattern(struct, operation.getIdentifier());
+ if (replacement != null) {
+ if (replacement.hasReplacement()) {
+ return replacement.getText();
+ }
+ return null;
+ }
+ return simpleName;
+ }
+ return simpleName;
+ }
+
+ /** Describes the result of a replacement.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+ public static class ConversionResult {
+
+ private final String text;
+
+ private final Object[] conversion;
+
+ /** Constructor for feature renaming.
+ *
+ * @param text the text.
+ */
+ protected ConversionResult(String text) {
+ this.text = text;
+ this.conversion = null;
+ }
+
+ /** Constructor for complex conversion.
+ *
+ * @param conversion is the description of the conversion.
+ */
+ protected ConversionResult(Object[] conversion) {
+ this.text = null;
+ this.conversion = conversion;
+ }
+
+ /** Replies if the replacement result is a simple feature renaming.
+ *
+ * @return {@code true} if the feature should be renamed, {@code false} for a complex replacement.
+ */
+ public boolean isFeatureRenaming() {
+ return !Strings.isEmpty(this.text);
+ }
+
+ /** Replies the complex conversion.
+ *
+ * The replied value is an array of {@link CharSequence}, {@link JvmType}, {@link LightweightTypeReference},
+ * or {@link XExpression}.
+ *
+ * @return the complex conversion.
+ */
+ public Object[] toComplexConversion() {
+ return this.conversion;
+ }
+
+ @Override
+ public String toString() {
+ return this.text;
+ }
+
+ }
+
+ /** Reader of the conversion rules.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+ public static class FeatureNameConverterRuleReader {
+
+ /** initialize the conversions mapping.
+ *
+ * @param result the result.
+ * @param pluginID the identifier of the generator's plugin.
+ * @param context the generation context.
+ * @return {@code true} if rules are read.
+ */
+ @SuppressWarnings("static-method")
+ public boolean initializeConversions(Map>> result,
+ String pluginID, IExtraLanguageGeneratorContext context) {
+ return false;
+ }
+
+ }
+
+ /** Feature pattern.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+ public static class FeaturePattern {
+
+ private static final String SEPARATOR_PATTERN = "\\/+"; //$NON-NLS-1$
+
+ private static final char ALL_PATTERN_CHAR = '*';
+
+ private static final String ALL_PATTERN = Character.toString(ALL_PATTERN_CHAR);
+
+ private static final String ANY_PATTERN = ".*"; //$NON-NLS-1$
+
+ private static final char OPARENTHESIS = '(';
+
+ private static final char CPARENTHESIS = ')';
+
+ private static final char SEPARATOR = '/';
+
+ private static final char DOT = '.';
+
+ private final boolean isNameReplacement;
+
+ private final String rawFeature;
+
+ private final Pattern featurePattern;
+
+ private final Pattern[] pathPatterns;
+
+ /** Constructor.
+ *
+ * The general format of the textual representation is:
+ *
+ * [path/]featureIdentifier
+ *
+ * The featureIdentifier
is the identifier of the feature.
+ * The path
is a sequence of type identifiers or field names.
+ *
+ * The special character *
may be used for specifying "anything".
+ *
+ * @param specification the textual representation of the pattern.
+ */
+ public FeaturePattern(String specification) {
+ final String[] elements = specification.split(SEPARATOR_PATTERN);
+ final String last = elements[elements.length - 1];
+ if (last.contains(ALL_PATTERN)) {
+ this.rawFeature = null;
+ this.featurePattern = Pattern.compile(protect(last));
+ } else {
+ this.rawFeature = last;
+ this.featurePattern = null;
+ }
+ this.pathPatterns = new Pattern[elements.length - 1];
+ if (this.pathPatterns.length > 0) {
+ for (int i = 0; i < this.pathPatterns.length; ++i) {
+ this.pathPatterns[i] = Pattern.compile(protect(elements[i]));
+ }
+ }
+ this.isNameReplacement = specification.charAt(specification.length() - 1) != CPARENTHESIS;
+ }
+
+ @Override
+ public String toString() {
+ if (this.rawFeature != null) {
+ return this.rawFeature;
+ }
+ return Objects.toString(this.featurePattern);
+ }
+
+ private static String protect(String source) {
+ if (Strings.equal(source, ALL_PATTERN)) {
+ return ANY_PATTERN;
+ }
+ final StringBuilder builder = new StringBuilder();
+ boolean first = true;
+ for (final String element : source.split(Pattern.quote(ALL_PATTERN))) {
+ if (first) {
+ first = false;
+ } else {
+ builder.append(ANY_PATTERN);
+ }
+ builder.append(Pattern.quote(element));
+ }
+ return builder.toString();
+ }
+
+ /** Replies if this pattern is only for a simple name replacement.
+ *
+ * @return {@code true} if the pattern corresponds to a simple name only.
+ */
+ public boolean isNameReplacement() {
+ return this.isNameReplacement;
+ }
+
+ /** Replies if the pattern matches the given identifier.
+ *
+ * @param feature the feature to test.
+ * @return {@code true} if the pattern matches.
+ */
+ public boolean matches(LinkedList feature) {
+ boolean match;
+ if (this.rawFeature != null) {
+ match = this.rawFeature.equals(feature.getLast());
+ } else {
+ final Matcher featureMatcher = this.featurePattern.matcher(feature.getLast());
+ match = featureMatcher.matches();
+ }
+ if (match && this.pathPatterns.length > 0) {
+ final Iterator iterator = feature.descendingIterator();
+ // Skip last
+ iterator.next();
+ for (int j = this.pathPatterns.length - 1;
+ match && iterator.hasNext() && j >= 0;
+ --j) {
+ final String component = iterator.next();
+ final Pattern pathPattern = this.pathPatterns[j];
+ final Matcher pathMatcher = pathPattern.matcher(component);
+ match = pathMatcher.matches();
+ }
+ }
+ return match;
+ }
+
+ /** Replies the simple name of the feature from the given textual representation.
+ *
+ * @param textualRepresentation the textual representation.
+ * @return the simple name.
+ */
+ public static String simpleName(String textualRepresentation) {
+ int start = textualRepresentation.lastIndexOf(SEPARATOR);
+ int end = textualRepresentation.length();
+ if (start < 0) {
+ start = 0;
+ } else {
+ ++start;
+ }
+ if (textualRepresentation.charAt(textualRepresentation.length() - 1) == CPARENTHESIS) {
+ end = textualRepresentation.lastIndexOf(OPARENTHESIS);
+ assert end > 0;
+ }
+ final int dot = textualRepresentation.lastIndexOf(DOT, end - 1);
+ if (dot + 1 >= start) {
+ start = dot + 1;
+ }
+ return textualRepresentation.substring(start, end);
+ }
+
+ }
+
+ /** Feature replacement.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+ public static class FeatureReplacement {
+
+ private static final char PROTECT_CHAR = '\\';
+
+ private static final char VARIABLE_CHAR = '$';
+
+ private static final char ALL_CHAR = '*';
+
+ private static final String ARGUMENT_SEPARATOR = ","; //$NON-NLS-1$
+
+ private final boolean hasReplacement;
+
+ private List staticParts = new ArrayList<>();
+
+ private List dynamicParts = new ArrayList<>();
+
+ private String raw;
+
+ /** Constructor.
+ *
+ * The general format of the textual representation may contains:
+ * $0
for the receiver.
+ * $n
for the n-th argument.
+ * $*
all the arguments.
+ *
+ *
+ * @param specification the textual representation of the pattern.
+ */
+ public FeatureReplacement(String specification) {
+ StringBuilder builder = new StringBuilder();
+ boolean isProtected = false;
+ StringBuilder isVariable = null;
+ int i = 0;
+ while (i < specification.length()) {
+ final char character = specification.charAt(i);
+ if (isProtected) {
+ isProtected = false;
+ builder.append(character);
+ ++i;
+ } else if (isVariable != null) {
+ if (character == ALL_CHAR && isVariable.length() == 0) {
+ this.dynamicParts.add(-1);
+ isVariable = null;
+ ++i;
+ } else if (character >= '0' && character <= '9') {
+ isVariable.append(character);
+ ++i;
+ } else {
+ final int varNumber = Integer.parseInt(isVariable.toString());
+ this.dynamicParts.add(varNumber);
+ isVariable = null;
+ }
+ } else {
+ switch (character) {
+ case PROTECT_CHAR:
+ isProtected = true;
+ break;
+ case VARIABLE_CHAR:
+ this.staticParts.add(builder.toString());
+ builder = new StringBuilder();
+ isVariable = new StringBuilder();
+ break;
+ default:
+ builder.append(character);
+ }
+ ++i;
+ }
+ }
+ if (isVariable != null) {
+ final int varNumber = Integer.parseInt(isVariable.toString());
+ this.dynamicParts.add(varNumber);
+ } else if (builder.length() > 0) {
+ this.staticParts.add(builder.toString());
+ }
+ this.hasReplacement = !specification.isEmpty();
+ this.raw = specification;
+ }
+
+ @Override
+ public String toString() {
+ return this.raw;
+ }
+
+ /** Replies if a replacement is defined.
+ *
+ * @return {@code true} if a replacement is defined.
+ */
+ public boolean hasReplacement() {
+ return this.hasReplacement;
+ }
+
+ /** Do the replacement.
+ *
+ * @param calledFeature the called feature.
+ * @param leftOperand the description of the elements into the left operand (usually, before assignment sign).
+ * @param receiver the description of the receiver, i.e. the object on which the feature is called.
+ * @param arguments the list of the arguments.
+ * @return the new simple name, or {@code null} if the equivalent function not exists,
+ * or {@code simpleName} if the function name should stay unchanged.
+ */
+ public ConversionResult replace(JvmIdentifiableElement calledFeature, List leftOperand,
+ List receiver, List arguments) {
+ assert this.hasReplacement;
+ if (!this.dynamicParts.isEmpty()) {
+ final List content = new ArrayList<>(this.staticParts.size() + this.dynamicParts.size());
+ final Iterator staticIterator = this.staticParts.iterator();
+ final Iterator dynamicIterator = this.dynamicParts.iterator();
+ while (staticIterator.hasNext()) {
+ assert staticIterator.hasNext();
+ content.add(staticIterator.next());
+ if (dynamicIterator.hasNext()) {
+ final int varNumber = dynamicIterator.next().intValue();
+ if (varNumber == -1) {
+ boolean first = true;
+ for (final XExpression arg : arguments) {
+ if (first) {
+ first = false;
+ } else {
+ content.add(ARGUMENT_SEPARATOR);
+ }
+ content.add(arg);
+ }
+ } else if (varNumber == 0) {
+ content.add(receiver.get(receiver.size() - 1));
+ } else if (varNumber > 0 && varNumber <= arguments.size()) {
+ content.add(arguments.get(varNumber - 1));
+ }
+ }
+ }
+ return new ConversionResult(content.toArray());
+ }
+ return new ConversionResult(this.staticParts.get(this.staticParts.size() - 1));
+ }
+
+ /** Replies the raw text for this replacement.
+ *
+ * @return the replacement text.
+ */
+ public String getText() {
+ return this.raw;
+ }
+
+ }
+
+ /** Type of feature conversion.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+ public enum ConversionType {
+
+ /** No conversion is allowed to the target language.
+ */
+ FORBIDDEN_CONVERSION,
+
+ /** Conversion is explicitly set.
+ */
+ EXPLICIT,
+
+ /** Implicit conversion. Usually, the feature remains the same.
+ */
+ IMPLICIT,
+
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageGeneratorContext.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageGeneratorContext.java
new file mode 100644
index 0000000000..5d8ba1aa26
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageGeneratorContext.java
@@ -0,0 +1,200 @@
+/*
+ * $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.generator.extra;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.UUID;
+
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.xtext.generator.IFileSystemAccess2;
+import org.eclipse.xtext.generator.IGeneratorContext;
+import org.eclipse.xtext.util.CancelIndicator;
+import org.eclipse.xtext.util.Strings;
+import org.eclipse.xtext.xbase.typesystem.references.LightweightTypeReference;
+
+/** The generator from SARL to the Python language.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public class ExtraLanguageGeneratorContext implements IExtraLanguageGeneratorContext {
+
+ private final UUID identifier;
+
+ private final Date generationDate;
+
+ private final IGeneratorContext delegate;
+
+ private final WeakReference rootGenerator;
+
+ private final Resource resource;
+
+ private IFileSystemAccess2 fileSystemAccess;
+
+ private Map temporaryData;
+
+ private LightweightTypeReference expectedExpressionType;
+
+ /** Create the context for the given delegate.
+ *
+ * @param delegate the delegate.
+ * @param fileSystemAccess the file system access.
+ * @param generator the root generator.
+ * @param resource the resource.
+ */
+ public ExtraLanguageGeneratorContext(IGeneratorContext delegate, IFileSystemAccess2 fileSystemAccess,
+ IRootGenerator generator, Resource resource) {
+ this.identifier = UUID.randomUUID();
+ this.generationDate = new Date();
+ this.delegate = delegate;
+ this.fileSystemAccess = fileSystemAccess;
+ this.resource = resource;
+ this.rootGenerator = new WeakReference<>(generator);
+ }
+
+ @Override
+ public UUID getGenerationID() {
+ return this.identifier;
+ }
+
+ @Override
+ public Date getGenerationDate() {
+ return this.generationDate;
+ }
+
+ @Override
+ public Resource getResource() {
+ return this.resource;
+ }
+
+ @Override
+ public IRootGenerator getRootGenerator() {
+ return this.rootGenerator.get();
+ }
+
+ @Override
+ public CancelIndicator getCancelIndicator() {
+ final CancelIndicator indicator = this.delegate.getCancelIndicator();
+ if (indicator == null) {
+ return CancelIndicator.NullImpl;
+ }
+ return indicator;
+ }
+
+ @Override
+ public IGeneratorContext getDelegate() {
+ return this.delegate;
+ }
+
+ @Override
+ public IFileSystemAccess2 getFileSystemAccess() {
+ return this.fileSystemAccess;
+ }
+
+ @Override
+ public T getData(String id, Class type, T defaultValue) {
+ if (Strings.isEmpty(id) || this.temporaryData == null) {
+ return defaultValue;
+ }
+ final Object data = this.temporaryData.get(id);
+ if (data == null) {
+ return defaultValue;
+ }
+ try {
+ return type.cast(data);
+ } catch (Throwable exception) {
+ return defaultValue;
+ }
+ }
+
+ @Override
+ public T getData(String id, Class type) {
+ return getData(id, type, null);
+ }
+
+ @Override
+ public void setData(String id, Object value) {
+ if (Strings.isEmpty(id)) {
+ return;
+ }
+ if (value == null) {
+ if (this.temporaryData != null) {
+ this.temporaryData.remove(id);
+ }
+ return;
+ }
+ if (this.temporaryData == null) {
+ this.temporaryData = new TreeMap<>();
+ }
+ this.temporaryData.put(id, value);
+ }
+
+ @Override
+ public void clearData() {
+ this.temporaryData = null;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public List getListData(String id, Class type) {
+ List list = null;
+ if (!Strings.isEmpty(id) && this.temporaryData != null) {
+ final Object obj = this.temporaryData.get(id);
+ if (obj instanceof List) {
+ list = (List) obj;
+ }
+ }
+ if (list == null) {
+ list = new ArrayList<>();
+ if (this.temporaryData == null) {
+ this.temporaryData = new TreeMap<>();
+ }
+ this.temporaryData.put(id, list);
+ }
+ return list;
+ }
+
+ @Override
+ public LightweightTypeReference getExpectedExpressionType() {
+ return this.expectedExpressionType;
+ }
+
+ @Override
+ public LightweightTypeReference setExpectedExpressionType(LightweightTypeReference expectedType) {
+ final LightweightTypeReference old = this.expectedExpressionType;
+ if (expectedType != null && expectedType.isPrimitiveVoid()) {
+ this.expectedExpressionType = null;
+ } else {
+ this.expectedExpressionType = expectedType;
+ }
+ return old;
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageImportManager.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageImportManager.java
new file mode 100644
index 0000000000..0dcf1a41b3
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageImportManager.java
@@ -0,0 +1,285 @@
+/*
+ * $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.generator.extra;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.xtext.common.types.JvmDeclaredType;
+import org.eclipse.xtext.common.types.JvmPrimitiveType;
+import org.eclipse.xtext.common.types.JvmType;
+import org.eclipse.xtext.common.types.JvmTypeParameter;
+import org.eclipse.xtext.common.types.JvmVoid;
+import org.eclipse.xtext.xbase.compiler.ImportManager;
+
+/** Import manager for SARL extra target languages.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public class ExtraLanguageImportManager extends ImportManager {
+
+ private final ExtraLanguageTypeConverter converter;
+
+ private Map wrappedImports;
+
+ private Character wrappedInternalSeparator;
+
+ private Set wrappedThisTypeSimpleNames;
+
+ private Set wrappedThisTypeQualifiedNames;
+
+ /** Constructor.
+ *
+ * @param converter the type conversion to be used.
+ */
+ public ExtraLanguageImportManager(ExtraLanguageTypeConverter converter) {
+ super(true);
+ this.converter = converter;
+ }
+
+ /** Constructor.
+ *
+ * @param converter the type conversion to be used.
+ * @param thisType the name of the current type.
+ */
+ public ExtraLanguageImportManager(ExtraLanguageTypeConverter converter, JvmDeclaredType thisType) {
+ super(true, thisType);
+ this.converter = converter;
+ }
+
+ /** Constructor.
+ *
+ * @param converter the type conversion to be used.
+ * @param innerSeparator the character to be used as inner separator.
+ */
+ public ExtraLanguageImportManager(ExtraLanguageTypeConverter converter, char innerSeparator) {
+ super(true, innerSeparator);
+ this.converter = converter;
+ }
+
+ /** Constructor.
+ *
+ * @param converter the type conversion to be used.
+ * @param thisType the name of the current type.
+ * @param innerSeparator the character to be used as inner separator.
+ */
+ public ExtraLanguageImportManager(ExtraLanguageTypeConverter converter,
+ JvmDeclaredType thisType, char innerSeparator) {
+ super(true, thisType, innerSeparator);
+ this.converter = converter;
+ }
+
+ /** Replies the internal set that contains the qualified names of "this" type.
+ *
+ * FIXME: Add into the super type (Xtext contribution).
+ *
+ * @return the internal set.
+ */
+ @SuppressWarnings("unchecked")
+ protected final Set internalGetThisTypeQualifiedNames() {
+ if (this.wrappedThisTypeQualifiedNames == null) {
+ try {
+ final Field field = ImportManager.class.getDeclaredField("thisTypeQualifiedNames"); //$NON-NLS-1$
+ field.setAccessible(true);
+ this.wrappedThisTypeQualifiedNames = (Set) field.get(this);
+ } catch (Exception exception) {
+ throw new Error(exception);
+ }
+ }
+ return this.wrappedThisTypeQualifiedNames;
+ }
+
+ /** Replies the internal set that contains the simple names of "this" type.
+ *
+ * FIXME: Add into the super type (Xtext contribution).
+ *
+ * @return the internal set.
+ */
+ @SuppressWarnings("unchecked")
+ protected final Set internalGetThisTypeSimpleNames() {
+ if (this.wrappedThisTypeSimpleNames == null) {
+ try {
+ final Field field = ImportManager.class.getDeclaredField("thisTypeSimpleNames"); //$NON-NLS-1$
+ field.setAccessible(true);
+ this.wrappedThisTypeSimpleNames = (Set) field.get(this);
+ } catch (Exception exception) {
+ throw new Error(exception);
+ }
+ }
+ return this.wrappedThisTypeSimpleNames;
+ }
+
+ /** Replies the internal import data structure.
+ *
+ * FIXME: Add into the super type (Xtext contribution).
+ *
+ * @return the internal import data structure.
+ */
+ @SuppressWarnings("unchecked")
+ protected final Map internalGetImports() {
+ if (this.wrappedImports == null) {
+ try {
+ final Field field = ImportManager.class.getDeclaredField("imports"); //$NON-NLS-1$
+ field.setAccessible(true);
+ this.wrappedImports = (Map) field.get(this);
+ } catch (Exception exception) {
+ throw new Error(exception);
+ }
+ }
+ return this.wrappedImports;
+ }
+
+ /** Replies the internal separator.
+ *
+ * FIXME: Add into the super type (Xtext contribution).
+ *
+ * @return the internal separator.
+ */
+ protected final char getInnerTypeSeparator() {
+ if (this.wrappedInternalSeparator == null) {
+ try {
+ final Field field = ImportManager.class.getDeclaredField("innerTypeSeparator"); //$NON-NLS-1$
+ field.setAccessible(true);
+ this.wrappedInternalSeparator = (Character) field.get(this);
+ } catch (Exception exception) {
+ throw new Error(exception);
+ }
+ }
+ return this.wrappedInternalSeparator.charValue();
+ }
+
+ /** Convert the given qualified name.
+ *
+ * @param name the given qualified name.
+ * @return the conversion result, or {@code null} if no type equivalent exists.
+ */
+ protected String convertQualifiedName(String name) {
+ return this.converter.convert(name);
+ }
+
+ private String getSimpleName(String name) {
+ if (name == null) {
+ return null;
+ }
+ final int index = name.lastIndexOf(getInnerTypeSeparator());
+ if (index < 0) {
+ return name;
+ }
+ return name.substring(index + 1);
+ }
+
+ @Override
+ public boolean addImportFor(JvmType type) {
+ final String qualifiedName = convertQualifiedName(type.getQualifiedName(getInnerTypeSeparator()));
+ if (qualifiedName == null) {
+ return false;
+ }
+ final String simpleName = getSimpleName(qualifiedName);
+ if (!allowsSimpleName(qualifiedName, simpleName) && !needsQualifiedName(qualifiedName, simpleName)
+ && !internalGetImports().containsKey(simpleName)) {
+ internalGetImports().put(simpleName, qualifiedName);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void appendType(Class> type, StringBuilder builder) {
+ if (type.isPrimitive()) {
+ final String qualifiedName = convertQualifiedName(type.getSimpleName());
+ if (qualifiedName == null) {
+ return;
+ }
+ builder.append(qualifiedName);
+ } else {
+ final String qualifiedName = convertQualifiedName(type.getCanonicalName());
+ if (qualifiedName == null) {
+ return;
+ }
+ if (!qualifiedName.contains(Character.toString(getInnerTypeSeparator()))) {
+ builder.append(qualifiedName);
+ return;
+ }
+ String nameToImport = qualifiedName;
+ String shortName = getSimpleName(qualifiedName);
+ String outerShortName = shortName;
+ if (shouldUseQualifiedNestedName(qualifiedName)) {
+ Class> outerContainer = type;
+ while (outerContainer.getDeclaringClass() != null) {
+ outerContainer = outerContainer.getDeclaringClass();
+ }
+ if (type != outerContainer) {
+ outerShortName = outerContainer.getSimpleName();
+ if (!internalGetThisTypeQualifiedNames().contains(outerContainer.getCanonicalName())
+ && internalGetThisTypeSimpleNames().contains(outerShortName)) {
+ outerShortName = qualifiedName;
+ shortName = qualifiedName;
+ } else {
+ nameToImport = outerContainer.getCanonicalName();
+ shortName = outerShortName + qualifiedName.substring(nameToImport.length());
+ }
+ }
+ }
+ appendType(qualifiedName, shortName, outerShortName, nameToImport, builder);
+ }
+ }
+
+ @Override
+ public void appendType(JvmType type, StringBuilder builder) {
+ final String qualifiedName = convertQualifiedName(type.getQualifiedName(getInnerTypeSeparator()));
+ if (qualifiedName == null) {
+ return;
+ }
+ if (type instanceof JvmPrimitiveType || type instanceof JvmVoid || type instanceof JvmTypeParameter
+ || !qualifiedName.contains(Character.toString(getInnerTypeSeparator()))) {
+ builder.append(qualifiedName);
+ } else {
+ String nameToImport = qualifiedName;
+ String shortName = getSimpleName(qualifiedName);
+ String outerShortName = shortName;
+ if (shouldUseQualifiedNestedName(qualifiedName)) {
+ JvmType outerContainer = type;
+ while (outerContainer.eContainer() instanceof JvmType) {
+ outerContainer = (JvmType) outerContainer.eContainer();
+ }
+ if (type != outerContainer) {
+ outerShortName = outerContainer.getSimpleName();
+ if (!internalGetThisTypeQualifiedNames().contains(outerContainer.getQualifiedName(getInnerTypeSeparator()))
+ && internalGetThisTypeSimpleNames().contains(outerShortName)) {
+ outerShortName = qualifiedName;
+ shortName = qualifiedName;
+ } else {
+ nameToImport = outerContainer.getQualifiedName(getInnerTypeSeparator());
+ shortName = outerShortName + qualifiedName.substring(nameToImport.length());
+ }
+ }
+ }
+ appendType(qualifiedName, shortName, outerShortName, nameToImport, builder);
+ }
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageOutputConfigurations.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageOutputConfigurations.java
new file mode 100644
index 0000000000..a11a36cb77
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageOutputConfigurations.java
@@ -0,0 +1,68 @@
+/*
+ * $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.generator.extra;
+
+import com.google.common.base.Strings;
+
+/** Utilities classes for the output configurations that are dedicated to the extra language generators.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public final class ExtraLanguageOutputConfigurations {
+
+ /** String of characters that should be appended to the output configuration's name
+ * in order to recognized the configuration as being associated to an extra language generator.
+ */
+ public static final String NAME_POSTFIX = ".extraLanguageGeneratorConfiguration"; //$NON-NLS-1$
+
+ private ExtraLanguageOutputConfigurations() {
+ //
+ }
+
+ /** Create and reply a name for an output configuration dedicated to the extra language generators.
+ *
+ *
Usually, the value of {@link #NAME_POSTFIX} is appended to the given identifier.
+ *
+ * @param generatorID the identifier of the generator.
+ * @return the name of the configuration.
+ */
+ public static String createOutputConfigurationName(String generatorID) {
+ return generatorID + NAME_POSTFIX;
+ }
+
+ /** Replies if the given name is one for an output configuration that is associated
+ * to a extra language generator.
+ *
+ *
Usually, the name has the postfix {@link #NAME_POSTFIX}.
+ *
+ * @param name the name to test.
+ * @return {@code true} if the given name is for an output configuration associated to an extra language generator.
+ */
+ public static boolean isExtraLanguageOutputConfiguration(String name) {
+ return Strings.nullToEmpty(name).endsWith(NAME_POSTFIX);
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageGenerator.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageSupportGenerator.java
similarity index 74%
rename from main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageGenerator.java
rename to main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageSupportGenerator.java
index 6efcd176fa..ed19300c8d 100644
--- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageGenerator.java
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageSupportGenerator.java
@@ -34,7 +34,6 @@
import org.eclipse.xtext.generator.IGenerator;
import org.eclipse.xtext.generator.IGenerator2;
import org.eclipse.xtext.generator.IGeneratorContext;
-import org.eclipse.xtext.util.CancelIndicator;
/** The generator from SARL to the default target language and an extra target language.
*
@@ -44,7 +43,7 @@
* @mavenartifactid $ArtifactId$
* @since 0.6
*/
-public class ExtraLanguageGenerator implements IGenerator, IGenerator2 {
+public class ExtraLanguageSupportGenerator implements IGenerator, IGenerator2 {
/** Name of the injected element for the main generator.
*/
@@ -122,27 +121,10 @@ public final void generate(Resource input, IFileSystemAccess2 fsa, IGeneratorCon
}
}
- /** Create the extra generator context from the given context.
- *
- * @param context the original context.
- * @return the extra context.
- */
- protected ExtraGeneratorContext getExtraGeneratorContext(IGeneratorContext context) {
- if (context instanceof ExtraGeneratorContext) {
- return (ExtraGeneratorContext) context;
- }
- final ExtraGeneratorContext extraContext = new ExtraGeneratorContext(
- context,
- getExtraGeneratorProvider().getGenerators(context));
- return extraContext;
- }
-
@Override
public final void doGenerate(Resource input, IFileSystemAccess fsa) {
final IFileSystemAccess2 casted = (IFileSystemAccess2) fsa;
- final GeneratorContext originalContext = new GeneratorContext();
- originalContext.setCancelIndicator(CancelIndicator.NullImpl);
- final ExtraGeneratorContext context = getExtraGeneratorContext(originalContext);
+ final GeneratorContext context = new GeneratorContext();
try {
beforeGenerate(input, casted, context);
doGenerate(input, casted, context);
@@ -153,16 +135,15 @@ public final void doGenerate(Resource input, IFileSystemAccess fsa) {
@Override
public void doGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) {
- final ExtraGeneratorContext extraContext = getExtraGeneratorContext(context);
final IGenerator2 mainGenerator = getMainGenerator();
if (mainGenerator != null) {
- mainGenerator.doGenerate(input, fsa, extraContext.getDelegate());
+ mainGenerator.doGenerate(input, fsa, context);
}
- final Iterable generators = extraContext.getExtraGenerators();
+ final Iterable generators = getExtraGeneratorProvider().getGenerators(context, input);
if (generators != null) {
for (final IGenerator2 generator : generators) {
try {
- generator.doGenerate(input, fsa, extraContext);
+ generator.doGenerate(input, fsa, context);
} catch (Throwable exception) {
getLogger().log(Level.SEVERE, exception.getLocalizedMessage(), exception);
}
@@ -172,16 +153,15 @@ public void doGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext
@Override
public void beforeGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) {
- final ExtraGeneratorContext extraContext = getExtraGeneratorContext(context);
final IGenerator2 mainGenerator = getMainGenerator();
if (mainGenerator != null) {
- mainGenerator.beforeGenerate(input, fsa, extraContext.getDelegate());
+ mainGenerator.beforeGenerate(input, fsa, context);
}
- final Iterable generators = extraContext.getExtraGenerators();
+ final Iterable generators = getExtraGeneratorProvider().getGenerators(context, input);
if (generators != null) {
for (final IGenerator2 generator : generators) {
try {
- generator.beforeGenerate(input, fsa, extraContext);
+ generator.beforeGenerate(input, fsa, context);
} catch (Throwable exception) {
getLogger().log(Level.SEVERE, exception.getLocalizedMessage(), exception);
}
@@ -191,16 +171,15 @@ public void beforeGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorCon
@Override
public void afterGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) {
- final ExtraGeneratorContext extraContext = getExtraGeneratorContext(context);
final IGenerator2 mainGenerator = getMainGenerator();
if (mainGenerator != null) {
- mainGenerator.afterGenerate(input, fsa, extraContext.getDelegate());
+ mainGenerator.afterGenerate(input, fsa, context);
}
- final Iterable generators = extraContext.getExtraGenerators();
+ final Iterable generators = getExtraGeneratorProvider().getGenerators(context, input);
if (generators != null) {
for (final IGenerator2 generator : generators) {
try {
- generator.afterGenerate(input, fsa, extraContext);
+ generator.afterGenerate(input, fsa, context);
} catch (Throwable exception) {
getLogger().log(Level.SEVERE, exception.getLocalizedMessage(), exception);
}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageTypeConverter.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageTypeConverter.java
new file mode 100644
index 0000000000..7d8c847ec7
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/ExtraLanguageTypeConverter.java
@@ -0,0 +1,151 @@
+/*
+ * $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.generator.extra;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+
+import javax.inject.Inject;
+
+/** Converter from Jvm type to the extra language type.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public final class ExtraLanguageTypeConverter {
+
+ private final IExtraLanguageConversionInitializer initializer;
+
+ private final IExtraLanguageGeneratorContext context;
+
+ private final String pluginID;
+
+ @Inject
+ private TypeConverterRuleReader converterReader;
+
+ private Map mapping;
+
+ /** Constructor.
+ *
+ * @param initializer the initializer.
+ * @param pluginID the identifier of the generator's plugin.
+ * @param context the generation ccontext.
+ */
+ public ExtraLanguageTypeConverter(IExtraLanguageConversionInitializer initializer,
+ String pluginID, IExtraLanguageGeneratorContext context) {
+ this.initializer = initializer;
+ this.context = context;
+ this.pluginID = pluginID;
+ }
+
+ /** Reset the mapping definition to its default content.
+ */
+ public void reset() {
+ this.mapping = null;
+ }
+
+ /** Build the mapping table.
+ *
+ * @return the mapping table.
+ */
+ protected Map initMapping() {
+ final Map map = new TreeMap<>();
+ if (!this.converterReader.initializeConversions(map, this.pluginID, this.context) && this.initializer != null) {
+ this.initializer.initializeConversions((simpleName, source, target) -> {
+ map.put(source, target);
+ });
+ }
+ return map;
+ }
+
+ /** Replies the type mapping.
+ *
+ * @return unmodifiable map of the type mapping.
+ */
+ public Map getMapping() {
+ if (this.mapping == null) {
+ this.mapping = initMapping();
+ }
+ return Collections.unmodifiableMap(this.mapping);
+ }
+
+ /** Indicates if the given name has a mapping to the extra language.
+ *
+ * @param type the type to convert.
+ * @return {@code true} if the mapping exists.
+ */
+ public boolean hasConversion(String type) {
+ if (this.mapping == null) {
+ this.mapping = initMapping();
+ }
+ return this.mapping.containsKey(type);
+ }
+
+ /** Convert the given type to its equivalent in the extra language.
+ *
+ * @param type the type to convert.
+ * @return the conversion result, or {@code null} if no equivalent exist.
+ */
+ public String convert(String type) {
+ if (this.mapping == null) {
+ this.mapping = initMapping();
+ }
+ final String map = this.mapping.get(type);
+ if (map != null) {
+ if (map.isEmpty()) {
+ return null;
+ }
+ return map;
+ }
+ return type;
+ }
+
+ /** Reader of the conversion rules.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+ public static class TypeConverterRuleReader {
+
+ /** initialize the conversions mapping.
+ *
+ * @param result the result.
+ * @param pluginID the identifier of the generator's plugin.
+ * @param context the generation context.
+ * @return {@code true} if rules are read.
+ */
+ @SuppressWarnings("static-method")
+ public boolean initializeConversions(Map result, String pluginID,
+ IExtraLanguageGeneratorContext context) {
+ return false;
+ }
+
+ }
+
+}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/IExpressionGenerator.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/IExpressionGenerator.java
new file mode 100644
index 0000000000..68e713f587
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/IExpressionGenerator.java
@@ -0,0 +1,75 @@
+/*
+ * $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.generator.extra;
+
+import org.eclipse.xtext.xbase.XExpression;
+import org.eclipse.xtext.xbase.compiler.IAppendable;
+import org.eclipse.xtext.xbase.typesystem.references.LightweightTypeReference;
+
+/** Generator of XExpression.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public interface IExpressionGenerator {
+
+ /** Generate the code for the given XExpression.
+ *
+ * The given expression is not expecting to be returned by a function.
+ *
+ * @param expression the expression to be generated.
+ * @param output the output.
+ * @param context the generator context.
+ * @return the lastly encountered expression.
+ */
+ default XExpression generate(XExpression expression, IAppendable output, IExtraLanguageGeneratorContext context) {
+ return generate(expression, null, output, context);
+ }
+
+ /** Generate the code for the given XExpression.
+ *
+ * @param expression the expression to be generated.
+ * @param expectedType the type that is expected for the expression in the context of a function return.
+ * @param output the output.
+ * @param context the generator context.
+ * @return the lastly encountered expression.
+ */
+ XExpression generate(XExpression expression, LightweightTypeReference expectedType, IAppendable output, IExtraLanguageGeneratorContext context);
+
+ /** Replies the type converter.
+ *
+ * @param context the context of the generation.
+ * @return the converter.
+ */
+ ExtraLanguageTypeConverter getTypeConverter(IExtraLanguageGeneratorContext context);
+
+ /** Replies the feature name converter.
+ *
+ * @param context the context of the generation.
+ * @return the converter.
+ */
+ ExtraLanguageFeatureNameConverter getFeatureNameConverter(IExtraLanguageGeneratorContext context);
+
+}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/IExtraLanguageConversionInitializer.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/IExtraLanguageConversionInitializer.java
new file mode 100644
index 0000000000..dacdc36206
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/IExtraLanguageConversionInitializer.java
@@ -0,0 +1,46 @@
+/*
+ * $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.generator.extra;
+
+import org.eclipse.xtext.xbase.lib.Procedures.Procedure3;
+
+/** Initializer for the extra language converters.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+@FunctionalInterface
+public interface IExtraLanguageConversionInitializer {
+
+ /** Initialize the conversions mapping.
+ *
+ * @param result the function to invoke for initializing the element.
+ * The first formal parameter is the simple name of the source.
+ * The second formal parameter is the full name of source of the conversion.
+ * The third formal parameter is the target of the conversion.
+ */
+ void initializeConversions(Procedure3 result);
+
+}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/IExtraLanguageGeneratorContext.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/IExtraLanguageGeneratorContext.java
new file mode 100644
index 0000000000..4c6d4fa53b
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/IExtraLanguageGeneratorContext.java
@@ -0,0 +1,141 @@
+/*
+ * $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.generator.extra;
+
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.xtext.generator.IFileSystemAccess2;
+import org.eclipse.xtext.generator.IGeneratorContext;
+import org.eclipse.xtext.xbase.typesystem.references.LightweightTypeReference;
+
+/** The generator from SARL to the Python language.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public interface IExtraLanguageGeneratorContext extends IGeneratorContext {
+
+ /** Replies an identifier for the generation.
+ *
+ * @return the identifier.
+ */
+ UUID getGenerationID();
+
+ /** Replies the date of the generation.
+ *
+ * @return the date.
+ */
+ Date getGenerationDate();
+
+ /** Replies the delegate.
+ *
+ * @return the delegate.
+ */
+ IGeneratorContext getDelegate();
+
+ /** Replies the root generator.
+ *
+ * @return the root generator.
+ */
+ IRootGenerator getRootGenerator();
+
+ /** Replies the resource from which the generation is done.
+ *
+ * @return the resource.
+ */
+ Resource getResource();
+
+ /** Replies the expected expression type in the context of a returnable expression
+ *
+ * If the given generated expression should be the expression to be returned by a function,
+ * this function replies a type, otherwise {@code null}.
+ *
+ * @return the expected type.
+ */
+ LightweightTypeReference getExpectedExpressionType();
+
+ /** Set the expected expression type in the context of a returnable expression
+ *
+ *
If the given generated expression should be the expression to be returned by a function,
+ * this function replies a type, otherwise {@code null}.
+ *
+ * @param expectedType the expected type, or {@code null} if the expression is not expected to be returned by
+ * a function.
+ * @return the value of the property before the change.
+ */
+ LightweightTypeReference setExpectedExpressionType(LightweightTypeReference expectedType);
+
+ /** Replies the file system access.
+ *
+ * @return the file system access.
+ */
+ IFileSystemAccess2 getFileSystemAccess();
+
+ /** Replies the stored data with the given identifier.
+ * If the data was not found, the default value is replied.
+ *
+ * @param the type of the data.
+ * @param id the identifier.
+ * @param type the type of the data.
+ * @param defaultValue the default value.
+ * @return the data or the default value.
+ */
+ T getData(String id, Class type, T defaultValue);
+
+ /** Replies the stored data with the given identifier.
+ * If the data was not found, the default value is replied.
+ *
+ * @param the type of the data.
+ * @param id the identifier.
+ * @param type the type of the data.
+ * @return the data or the default value.
+ */
+ T getData(String id, Class type);
+
+ /** Store data with the given identifier.
+ *
+ * @param id the identifier.
+ * @param value the value.
+ */
+ void setData(String id, Object value);
+
+ /** Clear all stored data.
+ */
+ void clearData();
+
+ /** Replies the stored data with the given identifier.
+ * If the data was not found, the default value is replied.
+ *
+ * @param the type of the data.
+ * @param id the identifier.
+ * @param type the type of the data.
+ * @return the data or the default value.
+ */
+ List getListData(String id, Class type);
+
+}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/IExtraLanguageGeneratorProvider.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/IExtraLanguageGeneratorProvider.java
index 2f51b30761..4f3084096e 100644
--- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/IExtraLanguageGeneratorProvider.java
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/IExtraLanguageGeneratorProvider.java
@@ -22,6 +22,7 @@
package io.sarl.lang.generator.extra;
import com.google.inject.ImplementedBy;
+import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.generator.IGenerator2;
import org.eclipse.xtext.generator.IGeneratorContext;
@@ -41,8 +42,9 @@ public interface IExtraLanguageGeneratorProvider {
/** Replies the generators that should be used for generating the extra language output files.
*
* @param context the generator context.
+ * @param resource the resource.
* @return the list of the generators.
*/
- Iterable getGenerators(IGeneratorContext context);
+ Iterable getGenerators(IGeneratorContext context, Resource resource);
}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/IRootGenerator.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/IRootGenerator.java
new file mode 100644
index 0000000000..c6742bab3a
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/IRootGenerator.java
@@ -0,0 +1,45 @@
+/*
+ * $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.generator.extra;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.generator.IGenerator2;
+
+/** Generator for SARL script.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public interface IRootGenerator extends IGenerator2 {
+
+ /** Generate the given object.
+ *
+ * @param object the object.
+ * @param appendable the target for the generated content.
+ * @param context the context.
+ */
+ void doGenerate(EObject object, ExtraLanguageAppendable appendable, IExtraLanguageGeneratorContext context);
+
+}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/NullExtraLanguageGeneratorProvider.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/NullExtraLanguageGeneratorProvider.java
index 3df4b7194c..3e28021d1e 100644
--- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/NullExtraLanguageGeneratorProvider.java
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/NullExtraLanguageGeneratorProvider.java
@@ -23,11 +23,10 @@
import java.util.Collections;
+import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.generator.IGenerator2;
import org.eclipse.xtext.generator.IGeneratorContext;
-import io.sarl.lang.generator.extra.python3.Python3Generator;
-
/** Implementation of the provider of the extra language generators that replies no generator.
*
* @author $Author: sgalland$
@@ -38,11 +37,9 @@
*/
public class NullExtraLanguageGeneratorProvider implements IExtraLanguageGeneratorProvider {
- private final Python3Generator generator = new Python3Generator();
-
@Override
- public Iterable getGenerators(IGeneratorContext context) {
- return Collections.singletonList(this.generator);
+ public Iterable getGenerators(IGeneratorContext context, Resource resource) {
+ return Collections.emptyList();
}
}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/python3/Python3Generator.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/python3/Python3Generator.java
deleted file mode 100644
index 0961d7170d..0000000000
--- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/generator/extra/python3/Python3Generator.java
+++ /dev/null
@@ -1,771 +0,0 @@
-/*
- * $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.generator.extra.python3;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-import javax.inject.Inject;
-
-import org.eclipse.xtend.core.xtend.AnonymousClass;
-import org.eclipse.xtend.core.xtend.XtendMember;
-import org.eclipse.xtend.core.xtend.XtendParameter;
-import org.eclipse.xtend.core.xtend.XtendTypeDeclaration;
-import org.eclipse.xtext.common.types.JvmTypeReference;
-import org.eclipse.xtext.common.types.JvmVisibility;
-import org.eclipse.xtext.naming.IQualifiedNameProvider;
-import org.eclipse.xtext.naming.QualifiedName;
-import org.eclipse.xtext.util.Strings;
-import org.eclipse.xtext.xbase.XAssignment;
-import org.eclipse.xtext.xbase.XBasicForLoopExpression;
-import org.eclipse.xtext.xbase.XBinaryOperation;
-import org.eclipse.xtext.xbase.XBlockExpression;
-import org.eclipse.xtext.xbase.XBooleanLiteral;
-import org.eclipse.xtext.xbase.XCasePart;
-import org.eclipse.xtext.xbase.XCastedExpression;
-import org.eclipse.xtext.xbase.XCatchClause;
-import org.eclipse.xtext.xbase.XClosure;
-import org.eclipse.xtext.xbase.XConstructorCall;
-import org.eclipse.xtext.xbase.XDoWhileExpression;
-import org.eclipse.xtext.xbase.XExpression;
-import org.eclipse.xtext.xbase.XFeatureCall;
-import org.eclipse.xtext.xbase.XForLoopExpression;
-import org.eclipse.xtext.xbase.XIfExpression;
-import org.eclipse.xtext.xbase.XInstanceOfExpression;
-import org.eclipse.xtext.xbase.XListLiteral;
-import org.eclipse.xtext.xbase.XMemberFeatureCall;
-import org.eclipse.xtext.xbase.XNullLiteral;
-import org.eclipse.xtext.xbase.XNumberLiteral;
-import org.eclipse.xtext.xbase.XPostfixOperation;
-import org.eclipse.xtext.xbase.XReturnExpression;
-import org.eclipse.xtext.xbase.XSetLiteral;
-import org.eclipse.xtext.xbase.XStringLiteral;
-import org.eclipse.xtext.xbase.XSwitchExpression;
-import org.eclipse.xtext.xbase.XSynchronizedExpression;
-import org.eclipse.xtext.xbase.XThrowExpression;
-import org.eclipse.xtext.xbase.XTryCatchFinallyExpression;
-import org.eclipse.xtext.xbase.XTypeLiteral;
-import org.eclipse.xtext.xbase.XUnaryOperation;
-import org.eclipse.xtext.xbase.XVariableDeclaration;
-import org.eclipse.xtext.xbase.XWhileExpression;
-import org.eclipse.xtext.xbase.compiler.IAppendable;
-
-import io.sarl.lang.generator.extra.AbstractExtraGenerator;
-import io.sarl.lang.sarl.SarlAnnotationType;
-import io.sarl.lang.sarl.SarlBreakExpression;
-import io.sarl.lang.sarl.SarlClass;
-import io.sarl.lang.sarl.SarlConstructor;
-import io.sarl.lang.sarl.SarlEnumeration;
-import io.sarl.lang.sarl.SarlField;
-import io.sarl.lang.sarl.SarlFormalParameter;
-import io.sarl.lang.sarl.SarlInterface;
-import io.sarl.lang.sarl.SarlScript;
-
-/** The generator from SARL to the Python language.
- *
- * @author $Author: sgalland$
- * @version $FullVersion$
- * @mavengroupid $GroupId$
- * @mavenartifactid $ArtifactId$
- * @since 0.6
- */
-@SuppressWarnings("checkstyle:classfanoutcomplexity")
-public class Python3Generator extends AbstractExtraGenerator {
-
- @Inject
- private IQualifiedNameProvider qualifiedNameProvider;
-
- private static String toModifierPrefix(XtendMember member) {
- final JvmVisibility visibility = member.getVisibility();
- if (visibility != null) {
- switch (visibility) {
- case PRIVATE:
- return "__"; //$NON-NLS-1$
- case DEFAULT:
- case PROTECTED:
- return "_"; //$NON-NLS-1$
- case PUBLIC:
- default:
- }
- }
- return ""; //$NON-NLS-1$
- }
-
- private static String toDefaultValue(JvmTypeReference type) {
- final String id = type.getIdentifier();
- if (!"void".equals(id)) { //$NON-NLS-1$
- switch (id) {
- case "boolean": //$NON-NLS-1$
- return "True"; //$NON-NLS-1$
- case "float": //$NON-NLS-1$
- case "double": //$NON-NLS-1$
- return "0.0"; //$NON-NLS-1$
- case "int": //$NON-NLS-1$
- case "long": //$NON-NLS-1$
- case "byte": //$NON-NLS-1$
- case "short": //$NON-NLS-1$
- return "0"; //$NON-NLS-1$
- case "char": //$NON-NLS-1$
- return "'\\0'"; //$NON-NLS-1$
- default:
- }
- }
- return "None"; //$NON-NLS-1$
- }
-
- @SuppressWarnings("checkstyle:npathcomplexity")
- private void generatePythonClass(XtendTypeDeclaration type, GeneratorContext context, String name,
- List superTypes, IAppendable it) {
- it.append("class ").append(name).append("("); //$NON-NLS-1$//$NON-NLS-2$
- if (!superTypes.isEmpty()) {
- boolean first = true;
- for (final JvmTypeReference reference : superTypes) {
- if (first) {
- first = false;
- } else {
- it.append(", "); //$NON-NLS-1$
- }
- it.append(reference.getType());
- }
- } else {
- it.append("object"); //$NON-NLS-1$
- }
- it.append("):"); //$NON-NLS-1$
- it.increaseIndentation().newLine();
-
- boolean foundMember = false;
-
- final List fields = new ArrayList<>();
- final List constructors = new ArrayList<>();
-
- for (final XtendMember member : type.getMembers()) {
- if (member instanceof XtendTypeDeclaration) {
- generate(member, context);
- } else if (member instanceof SarlField) {
- fields.add((SarlField) member);
- foundMember = true;
- } else if (member instanceof SarlConstructor) {
- constructors.add((SarlConstructor) member);
- foundMember = true;
- } else {
- generate(member, context, it);
- foundMember = true;
- }
- }
- if (!foundMember) {
- it.newLine();
- it.append("pass"); //$NON-NLS-1$
- } else if (constructors.isEmpty()) {
- if (!fields.isEmpty()) {
- it.append("def __init__(self):"); //$NON-NLS-1$
- it.increaseIndentation();
- generateFieldInitialization(fields, context, it);
- }
- } else {
- for (final SarlConstructor constructor : constructors) {
- it.append("def __init__"); //$NON-NLS-1$
- generateParameters(constructor.getParameters(), context, it);
- it.append(":"); //$NON-NLS-1$
- it.increaseIndentation();
- generateFieldInitialization(fields, context, it);
- if (constructor.getExceptions() != null) {
- generate(constructor.getExpression(), context, it);
- } else if (fields.isEmpty()) {
- it.newLine();
- it.append("pass"); //$NON-NLS-1$
- }
- }
- }
-
- it.decreaseIndentation().newLine();
- }
-
- private void generateParameters(List extends XtendParameter> parameters, GeneratorContext context, IAppendable it) {
- it.append("(self"); //$NON-NLS-1$
- for (final XtendParameter param : parameters) {
- it.append(", "); //$NON-NLS-1$
- if (param.isVarArg()) {
- it.append("*"); //$NON-NLS-1$
- }
- it.append(param.getName());
- if (param instanceof SarlFormalParameter) {
- final SarlFormalParameter sarlParameter = (SarlFormalParameter) param;
- if (sarlParameter.getDefaultValue() != null) {
- it.append(" = "); //$NON-NLS-1$
- generate(sarlParameter.getDefaultValue(), context, it);
- }
- }
- }
- it.append(")"); //$NON-NLS-1$
- }
-
- private void generateFieldInitialization(Iterable fields, GeneratorContext context, IAppendable it) {
- for (final SarlField field : fields) {
- it.newLine();
- it.append("self."); //$NON-NLS-1$
- it.append(toModifierPrefix(field));
- it.append(field.getName());
- it.append(" = "); //$NON-NLS-1$
- if (field.getInitialValue() != null) {
- generate(field.getInitialValue(), context, it);
- } else {
- it.append(toDefaultValue(field.getType()));
- }
- }
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- */
- protected void _generate(SarlScript object, GeneratorContext context) {
- for (final XtendTypeDeclaration type : object.getXtendTypes()) {
- if (context.getCancelIndicator().isCanceled()) {
- return;
- }
- final IAppendable appendable = new ExtraLanguageAppendable("\t", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
- generate(type, context, appendable);
- if (context.getCancelIndicator().isCanceled()) {
- return;
- }
- final String content = appendable.getContent();
- if (!Strings.isEmpty(content)) {
- final QualifiedName qualifiedName = this.qualifiedNameProvider.getFullyQualifiedName(type);
- final String fileName = qualifiedName.toString(File.separator) + ".py"; //$NON-NLS-1$
- context.getFileSystemAccess().generateFile(fileName, content);
- }
- }
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(SarlClass object, GeneratorContext context, IAppendable it) {
- if (!Strings.isEmpty(object.getName())) {
- final List superTypes = new ArrayList<>();
- if (object.getExtends() != null
- && !Objects.equals(object.getExtends().getIdentifier(), Object.class.getName())) {
- superTypes.add(object.getExtends());
- }
- for (final JvmTypeReference reference : object.getImplements()) {
- if (!Objects.equals(reference.getIdentifier(), Object.class.getName())) {
- superTypes.add(reference);
- }
- }
- generatePythonClass(object, context, object.getName(), superTypes, it);
- }
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(SarlInterface object, GeneratorContext context, IAppendable it) {
- if (!Strings.isEmpty(object.getName())) {
- final List superTypes = new ArrayList<>();
- for (final JvmTypeReference reference : object.getExtends()) {
- if (!Objects.equals(reference.getIdentifier(), Object.class.getName())) {
- superTypes.add(reference);
- }
- }
- generatePythonClass(object, context, object.getName(), superTypes, it);
- }
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(SarlEnumeration object, GeneratorContext context, IAppendable it) {
- if (!Strings.isEmpty(object.getName())) {
- generatePythonClass(object, context, object.getName(), Collections.emptyList(), it);
- }
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(SarlAnnotationType object, GeneratorContext context, IAppendable it) {
- if (!Strings.isEmpty(object.getName())) {
- generatePythonClass(object, context, object.getName(), Collections.emptyList(), it);
- }
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- @SuppressWarnings("static-method")
- protected void _generate(SarlBreakExpression object, GeneratorContext context, IAppendable it) {
- it.append("break"); //$NON-NLS-1$
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XAssignment object, GeneratorContext context, IAppendable it) {
- //TODO
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XBinaryOperation object, GeneratorContext context, IAppendable it) {
- //TODO
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XFeatureCall object, GeneratorContext context, IAppendable it) {
- //TODO
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XMemberFeatureCall object, GeneratorContext context, IAppendable it) {
- //TODO
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XPostfixOperation object, GeneratorContext context, IAppendable it) {
- //TODO
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XUnaryOperation object, GeneratorContext context, IAppendable it) {
- //TODO
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XConstructorCall object, GeneratorContext context, IAppendable it) {
- //TODO
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XClosure object, GeneratorContext context, IAppendable it) {
- //TODO
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(AnonymousClass object, GeneratorContext context, IAppendable it) {
- //TODO
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XDoWhileExpression object, GeneratorContext context, IAppendable it) {
- if (object.getBody() != null) {
- it.newLine();
- it.append("___condition = "); //$NON-NLS-1$
- generate(object.getPredicate(), context, it);
- it.newLine();
- it.append("while ___condition:"); //$NON-NLS-1$
- it.increaseIndentation().newLine();
- generate(object.getBody(), context, it);
- it.newLine();
- it.append("___condition = "); //$NON-NLS-1$
- generate(object.getPredicate(), context, it);
- it.decreaseIndentation();
- }
- }
-
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XWhileExpression object, GeneratorContext context, IAppendable it) {
- if (object.getBody() != null) {
- it.newLine();
- it.append("while "); //$NON-NLS-1$
- generate(object.getPredicate(), context, it);
- it.append(":"); //$NON-NLS-1$
- it.increaseIndentation().newLine();
- generate(object.getBody(), context, it);
- it.decreaseIndentation();
- }
- }
-
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XBasicForLoopExpression object, GeneratorContext context, IAppendable it) {
- if (object.getExpression() != null) {
- for (final XExpression initExpr : object.getInitExpressions()) {
- generate(initExpr, context, it);
- }
- it.newLine();
- it.append("while "); //$NON-NLS-1$
- generate(object.getEachExpression(), context, it);
- it.append(":"); //$NON-NLS-1$
- it.increaseIndentation().newLine();
- generate(object.getExpression(), context, it);
- for (final XExpression initExpr : object.getUpdateExpressions()) {
- generate(initExpr, context, it);
- }
- it.decreaseIndentation();
- }
- }
-
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XBlockExpression object, GeneratorContext context, IAppendable it) {
- for (final XExpression expr : object.getExpressions()) {
- it.increaseIndentation();
- generate(expr, context, it);
- it.decreaseIndentation();
- }
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- @SuppressWarnings("static-method")
- protected void _generate(XBooleanLiteral object, GeneratorContext context, IAppendable it) {
- it.append(object.isIsTrue() ? "True" : "False"); //$NON-NLS-1$ //$NON-NLS-2$
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XCastedExpression object, GeneratorContext context, IAppendable it) {
- generate(object.getTarget(), context, it);
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XListLiteral object, GeneratorContext context, IAppendable it) {
- it.append("["); //$NON-NLS-1$
- boolean first = true;
- for (final XExpression value : object.getElements()) {
- if (first) {
- first = false;
- } else {
- it.append(", "); //$NON-NLS-1$
- }
- generate(value, context, it);
- }
- it.append("["); //$NON-NLS-1$
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XSetLiteral object, GeneratorContext context, IAppendable it) {
- it.append("{"); //$NON-NLS-1$
- boolean first = true;
- for (final XExpression value : object.getElements()) {
- if (first) {
- first = false;
- } else {
- it.append(", "); //$NON-NLS-1$
- }
- generate(value, context, it);
- }
- it.append("}"); //$NON-NLS-1$
- }
-
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XForLoopExpression object, GeneratorContext context, IAppendable it) {
- //TODO
- }
-
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XIfExpression object, GeneratorContext context, IAppendable it) {
- if (object.getElse() != null || object.getThen() != null) {
- it.append("if "); //$NON-NLS-1$
- generate(object.getIf(), context, it);
- it.append(":"); //$NON-NLS-1$
- it.increaseIndentation().newLine();
- if (object.getThen() != null) {
- generate(object.getThen(), context, it);
- } else {
- it.append("pass"); //$NON-NLS-1$
- }
- it.decreaseIndentation();
- if (object.getElse() != null) {
- it.append("else:"); //$NON-NLS-1$
- it.increaseIndentation().newLine();
- generate(object.getElse(), context, it);
- it.decreaseIndentation();
- }
- }
- }
-
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XInstanceOfExpression object, GeneratorContext context, IAppendable it) {
- it.append("isinstance("); //$NON-NLS-1$
- generate(object.getExpression(), context, it);
- it.append(", "); //$NON-NLS-1$
- it.append(object.getType().getType());
- it.append(")"); //$NON-NLS-1$
- }
-
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- @SuppressWarnings("static-method")
- protected void _generate(XNullLiteral object, GeneratorContext context, IAppendable it) {
- it.append("None"); //$NON-NLS-1$
- }
-
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- @SuppressWarnings("static-method")
- protected void _generate(XNumberLiteral object, GeneratorContext context, IAppendable it) {
- it.append(object.getValue());
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XReturnExpression object, GeneratorContext context, IAppendable it) {
- it.append("return "); //$NON-NLS-1$
- generate(object.getExpression(), context, it);
- }
-
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- @SuppressWarnings("static-method")
- protected void _generate(XStringLiteral object, GeneratorContext context, IAppendable it) {
- it.append("\"").append(Strings.convertToJavaString(object.getValue())).append("\""); //$NON-NLS-1$//$NON-NLS-2$
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XSwitchExpression object, GeneratorContext context, IAppendable it) {
- it.append("___expression = "); //$NON-NLS-1$
- generate(object.getSwitch(), context, it);
- boolean first = true;
- for (final XCasePart caseExpression : object.getCases()) {
- if (first) {
- it.append("if "); //$NON-NLS-1$
- first = false;
- } else {
- it.append("elif "); //$NON-NLS-1$
- }
- it.append("___expression == "); //$NON-NLS-1$
- generate(caseExpression.getCase(), context, it);
- it.append(":"); //$NON-NLS-1$
- it.increaseIndentation().newLine();
- generate(caseExpression.getThen(), context, it);
- it.decreaseIndentation().newLine();
- }
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XSynchronizedExpression object, GeneratorContext context, IAppendable it) {
- generate(object.getExpression(), context, it);
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XThrowExpression object, GeneratorContext context, IAppendable it) {
- it.append("raise "); //$NON-NLS-1$
- generate(object.getExpression(), context, it);
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XTryCatchFinallyExpression object, GeneratorContext context, IAppendable it) {
- if (!object.getCatchClauses().isEmpty() || object.getFinallyExpression() != null) {
- it.append("try:"); //$NON-NLS-1$
- it.increaseIndentation().newLine();
- generate(object.getExpression(), context, it);
- it.decreaseIndentation();
- for (final XCatchClause clause : object.getCatchClauses()) {
- it.newLine();
- it.append("except "); //$NON-NLS-1$
- generate(clause.getExpression(), context, it);
- it.append(":"); //$NON-NLS-1$
- it.increaseIndentation().newLine();
- generate(clause.getExpression(), context, it);
- it.decreaseIndentation();
- }
- }
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- @SuppressWarnings("static-method")
- protected void _generate(XTypeLiteral object, GeneratorContext context, IAppendable it) {
- it.append(object.getType());
- }
-
- /** Generate the given object.
- *
- * @param object the object.
- * @param context the context.
- * @param it the target for the generated content.
- */
- protected void _generate(XVariableDeclaration object, GeneratorContext context, IAppendable it) {
- it.append(object.getName());
- it.append(" = "); //$NON-NLS-1$
- if (object.getRight() != null) {
- generate(object.getRight(), context, it);
- } else if (object.getType() != null) {
- it.append(toDefaultValue(object.getType()));
- } else {
- it.append("None"); //$NON-NLS-1$
- }
- }
-
-}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/jvmmodel/Messages.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/jvmmodel/Messages.java
index b9c0ff8243..868cc28fff 100644
--- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/jvmmodel/Messages.java
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/jvmmodel/Messages.java
@@ -31,7 +31,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.lang.jvmmodel.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
public static String SARLJvmModelInferrer_0;
public static String SARLJvmModelInferrer_2;
public static String SARLJvmModelInferrer_5;
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/parser/Messages.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/parser/Messages.java
index 57c382f047..929e0ff801 100644
--- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/parser/Messages.java
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/parser/Messages.java
@@ -32,7 +32,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.lang.parser.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
public static String SARLSyntaxErrorMessageProvider_0;
public static String SARLSyntaxErrorMessageProvider_1;
static {
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/util/Utils.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/util/Utils.java
index b6030c9cac..25cb09b526 100644
--- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/util/Utils.java
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/util/Utils.java
@@ -1207,7 +1207,7 @@ public static boolean getContainerNotOfType(EObject element, Class extends EOb
* @since 0.5
* @see EcoreUtil2#getContainerOfType(EObject, Class)
*/
- public static EObject getFirstContainerNotOfType(EObject element, Function1 predicate) {
+ public static EObject getFirstContainerForPredicate(EObject element, Function1 predicate) {
if (predicate == null || element == null) {
return null;
}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/IssueCodes.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/IssueCodes.java
index 2d5d0ea025..52bc882586 100644
--- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/IssueCodes.java
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/IssueCodes.java
@@ -169,6 +169,13 @@ public final class IssueCodes {
public static final String INVALID_USE_OF_BREAK =
ISSUE_CODE_PREFIX + "invalid_use_of_break"; //$NON-NLS-1$
+ /**
+ * Invalid extr-language generation.
+ * @since 0.6
+ */
+ public static final String INVALID_EXTRA_LANGUAGE_GENERATION =
+ ISSUE_CODE_PREFIX + "invalid_extra_language_generation"; //$NON-NLS-1$
+
private IssueCodes() {
//
}
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/Messages.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/Messages.java
index e6234bfefe..912c8138a3 100644
--- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/Messages.java
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/Messages.java
@@ -31,7 +31,7 @@
*/
@SuppressWarnings("all")
public class Messages extends NLS {
- private static final String BUNDLE_NAME = "io.sarl.lang.validation.messages"; //$NON-NLS-1$
+ private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/SARLValidator.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/SARLValidator.java
index 42162f1847..719dd3efe0 100644
--- a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/SARLValidator.java
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/SARLValidator.java
@@ -2246,7 +2246,7 @@ public void checkUnmodifiableEventAccess(SarlBehaviorUnit unit) {
*/
@Check
public void checkBreakKeywordUse(SarlBreakExpression expression) {
- final EObject container = Utils.getFirstContainerNotOfType(expression,
+ final EObject container = Utils.getFirstContainerForPredicate(expression,
(it) -> !(it instanceof XExpression) || it instanceof XAbstractWhileExpression
|| it instanceof XBasicForLoopExpression || it instanceof XForLoopExpression);
if (container instanceof XExpression) {
diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/extra/AbstractExtraLanguageValidator.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/extra/AbstractExtraLanguageValidator.java
new file mode 100644
index 0000000000..ebe19a7015
--- /dev/null
+++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/extra/AbstractExtraLanguageValidator.java
@@ -0,0 +1,319 @@
+/*
+ * $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.validation.extra;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.TreeSet;
+
+import javax.inject.Inject;
+
+import com.google.inject.Injector;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.common.types.JvmIdentifiableElement;
+import org.eclipse.xtext.common.types.JvmType;
+import org.eclipse.xtext.validation.ValidationMessageAcceptor;
+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.lib.Functions.Function2;
+import org.eclipse.xtext.xbase.lib.Procedures.Procedure3;
+import org.eclipse.xtext.xbase.validation.AbstractXbaseValidator;
+
+import io.sarl.lang.generator.extra.ExtraLanguageFeatureNameConverter;
+import io.sarl.lang.generator.extra.ExtraLanguageFeatureNameConverter.ConversionType;
+import io.sarl.lang.generator.extra.ExtraLanguageTypeConverter;
+import io.sarl.lang.generator.extra.IExtraLanguageConversionInitializer;
+import io.sarl.lang.generator.extra.IExtraLanguageGeneratorContext;
+import io.sarl.lang.util.Utils;
+import io.sarl.lang.validation.IssueCodes;
+
+/** The abstract implementation of a validator for an extra target language.
+ *
+ * @author $Author: sgalland$
+ * @version $FullVersion$
+ * @mavengroupid $GroupId$
+ * @mavenartifactid $ArtifactId$
+ * @since 0.6
+ */
+public abstract class AbstractExtraLanguageValidator extends AbstractXbaseValidator {
+
+ private static final String CHECKED_FEATURE_CALLS = "io.sarl.lang.validation.extra.CheckedFeatureCalls"; //$NON-NLS-1$
+
+ private ExtraLanguageTypeConverter typeConverter;
+
+ private ExtraLanguageFeatureNameConverter featureConverter;
+
+ @Inject
+ private Injector injector;
+
+ @Override
+ public void setInjector(Injector injector) {
+ super.setInjector(injector);
+ this.injector = injector;
+ }
+
+ /** Generate an error for the extra-language.
+ *
+ * This function generates an error, a warning, or an information depending on the extra-language generation's
+ * configuration.
+ *
+ * @param message the error message.
+ * @param source the source of the error.
+ */
+ protected void error(String message, EObject source) {
+ error(message, source,
+ null,
+ ValidationMessageAcceptor.INSIGNIFICANT_INDEX,
+ IssueCodes.INVALID_EXTRA_LANGUAGE_GENERATION);
+ }
+
+ /** Replies the initializer for the type converter.
+ *
+ * @return the initializer.
+ */
+ protected abstract IExtraLanguageConversionInitializer getTypeConverterInitializer();
+
+ /** Replies the initializer for the feature converter.
+ *
+ * @return the initializer.
+ */
+ protected abstract IExtraLanguageConversionInitializer getFeatureConverterInitializer();
+
+ /** Replies the identifier of the generator's plugin.
+ *
+ * @return the plugin's identifier.
+ */
+ protected abstract String getGeneratorPluginID();
+
+ /** Replies the type converter.
+ *
+ * @return the type converter.
+ */
+ public ExtraLanguageTypeConverter getTypeConverter() {
+ ExtraLanguageTypeConverter converter = this.typeConverter;
+ if (converter == null) {
+ converter = createTypeConverterInstance(getTypeConverterInitializer(), getGeneratorPluginID(), null);
+ this.injector.injectMembers(converter);
+ this.typeConverter = converter;
+ }
+ return converter;
+ }
+
+ /** Create the instance of the type converter.
+ *
+ * @param initializer the converter initializer.
+ * @param pluginID the identifier of the generator's plugin.
+ * @param context the genetation context.
+ * @return the type converter.
+ */
+ @SuppressWarnings("static-method")
+ protected ExtraLanguageTypeConverter createTypeConverterInstance(
+ IExtraLanguageConversionInitializer initializer,
+ String pluginID,
+ IExtraLanguageGeneratorContext context) {
+ return new ExtraLanguageTypeConverter(initializer, pluginID, context);
+ }
+
+ /** Replies the feature name converter.
+ *
+ * @return the feature name converter.
+ */
+ public ExtraLanguageFeatureNameConverter getFeatureNameConverter() {
+ ExtraLanguageFeatureNameConverter converter = this.featureConverter;
+ if (converter == null) {
+ converter = createFeatureNameConverterInstance(getFeatureConverterInitializer(), getGeneratorPluginID(), null);
+ this.injector.injectMembers(converter);
+ this.featureConverter = converter;
+ }
+ return converter;
+ }
+
+ /** Create the instance of the feature name converter.
+ *
+ * @param initializer the converter initializer.
+ * @param pluginID the identifier of the generator's plugin.
+ * @param context the genetation context.
+ * @return the feature name converter.
+ */
+ @SuppressWarnings("static-method")
+ protected ExtraLanguageFeatureNameConverter createFeatureNameConverterInstance(
+ IExtraLanguageConversionInitializer initializer,
+ String pluginID,
+ IExtraLanguageGeneratorContext context) {
+ return new ExtraLanguageFeatureNameConverter(initializer, pluginID, context);
+ }
+
+ /** Do a type mapping check.
+ *
+ * @param source the source of the type.
+ * @param type the type to check.
+ * @param errorHandler the error handler.
+ * @return {@code true} if a type mapping is defined.
+ */
+ protected boolean doTypeMappingCheck(EObject source, JvmType type, Procedure3 errorHandler) {
+ if (source != null && type != null) {
+ final ExtraLanguageTypeConverter converter = getTypeConverter();
+ final String qn = type.getQualifiedName();
+ if (converter != null && !converter.hasConversion(qn)) {
+ if (errorHandler != null) {
+ errorHandler.apply(source, type, qn);
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ protected boolean isResponsible(Map context, EObject eObject) {
+ if (!super.isResponsible(context, eObject)) {
+ return false;
+ }
+ // Skip the validation of an feature call if one of its container was validated previously
+ if (eObject instanceof XMemberFeatureCall || eObject instanceof XFeatureCall) {
+ final XAbstractFeatureCall rootFeatureCall = getRootFeatureCall((XAbstractFeatureCall) eObject);
+ return !isCheckedFeatureCall(context, rootFeatureCall);
+ }
+ return true;
+ }
+
+ private static boolean isCheckedFeatureCall(Map context, EObject eObject) {
+ if (eObject instanceof XMemberFeatureCall || eObject instanceof XFeatureCall) {
+ final Object calls = context.get(CHECKED_FEATURE_CALLS);
+ if (calls != null && ((Collection>) calls).contains(eObject)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static void setCheckedFeatureCall(Map context, EObject eObject) {
+ if (eObject instanceof XMemberFeatureCall || eObject instanceof XFeatureCall) {
+ Collection calls = (Collection) context.get(CHECKED_FEATURE_CALLS);
+ if (calls == null) {
+ calls = new TreeSet<>(FeatureCallComparator.SINGLETON);
+ context.put(CHECKED_FEATURE_CALLS, calls);
+ }
+ calls.add((XAbstractFeatureCall) eObject);
+ }
+ }
+
+ /** Check if the feature call could be translated to the extra-language.
+ *
+ * @param featureCall the feature call.
+ * @param typeErrorHandler the error handler for the type conversion.
+ * @param featureErrorHandler the error handler for the feature call conversion.
+ */
+ protected void doCheckMemberFeatureCallMapping(XAbstractFeatureCall featureCall,
+ Procedure3 typeErrorHandler,
+ Function2 featureErrorHandler) {
+ final XAbstractFeatureCall rootFeatureCall = getRootFeatureCall(featureCall);
+ final Map context = getContext();
+ if (isCheckedFeatureCall(context, rootFeatureCall)) {
+ // One of the containing expressions was already checked.
+ return;
+ }
+ // Mark the root container as validated.
+ setCheckedFeatureCall(context, rootFeatureCall);
+ // Validate the current call.
+ internalCheckMemberFeaturCallMapping(rootFeatureCall, typeErrorHandler, featureErrorHandler);
+ }
+
+ private static XAbstractFeatureCall getRootFeatureCall(XAbstractFeatureCall featureCall) {
+ final EObject container = featureCall.eContainer();
+ final XAbstractFeatureCall rootFeatureCall;
+ if (container instanceof XMemberFeatureCall || container instanceof XFeatureCall) {
+ rootFeatureCall = (XAbstractFeatureCall) Utils.getFirstContainerForPredicate(featureCall,
+ (it) -> it.eContainer() != null && !(it.eContainer() instanceof XMemberFeatureCall || it.eContainer() instanceof XFeatureCall));
+ } else {
+ rootFeatureCall = featureCall;
+ }
+ return rootFeatureCall;
+ }
+
+ private boolean internalCheckMemberFeaturCallMapping(XAbstractFeatureCall featureCall,
+ Procedure3