diff --git a/contribs/io.sarl.experienceindex/io.sarl.experienceindex.plugin/src/io/sarl/experienceindex/Messages.sarl b/contribs/io.sarl.experienceindex/io.sarl.experienceindex.plugin/src/io/sarl/experienceindex/Messages.sarl index e6204ba909..4bf0c63f99 100644 --- a/contribs/io.sarl.experienceindex/io.sarl.experienceindex.plugin/src/io/sarl/experienceindex/Messages.sarl +++ b/contribs/io.sarl.experienceindex/io.sarl.experienceindex.plugin/src/io/sarl/experienceindex/Messages.sarl @@ -34,7 +34,7 @@ import org.eclipse.osgi.util.NLS final class Messages extends NLS { private static val BUNDLE_NAME = { - val name = "io.sarl.experienceindex.messages" + val name = typeof(Messages).getPackage.name + ".messages" // initialize resource bundle NLS.initializeMessages(name, typeof(Messages)) name diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.feature/build.properties b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.feature/build.properties new file mode 100644 index 0000000000..64f93a9f0b --- /dev/null +++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.feature/feature.xml b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.feature/feature.xml new file mode 100644 index 0000000000..5e9cf1090d --- /dev/null +++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.feature/feature.xml @@ -0,0 +1,244 @@ + + + + + Provide the generator to the SARL compiler for generating Python programs. + + + + Copyright (c) 2017 the original authors and authors. + + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.feature/pom.xml b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.feature/pom.xml new file mode 100644 index 0000000000..5165ad6e3a --- /dev/null +++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.feature/pom.xml @@ -0,0 +1,26 @@ + + 4.0.0 + + io.sarl.pythongenerator + io.sarl.pythongenerator + 0.6.0-SNAPSHOT + + + io.sarl.pythongenerator.feature + eclipse-feature + Python Generator Feature + + + + + org.eclipse.tycho.extras + tycho-source-feature-plugin + + + org.eclipse.tycho + tycho-p2-plugin + + + + diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/META-INF/MANIFEST.MF b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..683b1d79cf --- /dev/null +++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/META-INF/MANIFEST.MF @@ -0,0 +1,26 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-SymbolicName: io.sarl.pythongenerator.plugin;singleton:=true +Bundle-Version: 0.6.0.qualifier +Bundle-Vendor: %Bundle-Vendor +Bundle-Name: %Bundle-Name +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Bundle-ActivationPolicy: lazy +Require-Bundle: io.sarl.lang;bundle-version="0.6.0", + io.sarl.lang.ui;bundle-version="0.6.0", + io.sarl.eclipse;bundle-version="0.6.0", + org.eclipse.xtext;bundle-version="2.12.0", + org.eclipse.xtext.xbase;bundle-version="2.12.0", + org.eclipse.xtext.util;bundle-version="2.12.0", + org.eclipse.xtext.ui;bundle-version="2.12.0", + org.eclipse.xtend.core;bundle-version="2.12.0", + javax.inject;bundle-version="1.0.0", + org.eclipse.osgi;bundle-version="3.11.3", + org.eclipse.ui.forms;bundle-version="3.7.1", + org.eclipse.xtext.builder;bundle-version="2.12.0" +Export-Package: io.sarl.pythongenerator, + io.sarl.pythongenerator.configuration, + io.sarl.pythongenerator.generator, + io.sarl.pythongenerator.ui, + io.sarl.pythongenerator.validator +Bundle-Activator: io.sarl.pythongenerator.PyGeneratorPlugin diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/OSGI-INF/l10n/bundle.properties b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/OSGI-INF/l10n/bundle.properties new file mode 100644 index 0000000000..956b7670da --- /dev/null +++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/OSGI-INF/l10n/bundle.properties @@ -0,0 +1,3 @@ +Bundle-Vendor = SARL.io +Bundle-Name = Python Generator for SARL +preference.page = Python diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/build.properties b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/build.properties new file mode 100644 index 0000000000..ab18f151da --- /dev/null +++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/build.properties @@ -0,0 +1,9 @@ +source.. = src +bin.includes = META-INF/,\ + OSGI-INF/,\ + .,\ + icons/,\ + conversions/,\ + plugin.xml +jre.compilation.profile = JavaSE-1.8 + diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/conversions/feature_name_conversion.properties b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/conversions/feature_name_conversion.properties new file mode 100644 index 0000000000..b072ea4909 --- /dev/null +++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/conversions/feature_name_conversion.properties @@ -0,0 +1,14 @@ +# Keywords +this = self +super = super() + +# Function declarations (no parentheses at the end of the keys) +*.toString = __str__ +*.equals = __eq__ +*.hashCode = __hash__ + +# Function Calls (parentheses at the end of the keys) +*.toString() = str($0) +*.equals(java.lang.Object) = ($0 == $1) +*.hashCode() = hash($0) +java.lang.System/*/java.io.PrintStream.print*(*) = print($*) diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/conversions/type_conversion.properties b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/conversions/type_conversion.properties new file mode 100644 index 0000000000..a2c5b86dce --- /dev/null +++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/conversions/type_conversion.properties @@ -0,0 +1,29 @@ +boolean = bool +byte = int +short = int +long = long +double = float +char = unicode + +java.lang.Object = object + +java.lang.Boolean = bool +java.lang.Byte = int +java.lang.Short = int +java.lang.Integer = int +java.lang.Long = long +java.lang.Float = float +java.lang.Double = float + +java.lang.Character = unicode +java.lang.String = unicode + +java.util.Set = set +java.util.TreeSet = set +java.util.HashSet = set + +java.util.Map = dict +java.util.TreeMap = dict +java.util.HashMap = dict + +java.io.File = file diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/icons/python.png b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/icons/python.png new file mode 100644 index 0000000000..76b6c1d7ff Binary files /dev/null and b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/icons/python.png differ diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/plugin.xml b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/plugin.xml new file mode 100644 index 0000000000..df2d4e2bdb --- /dev/null +++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/plugin.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/pom.xml b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/pom.xml new file mode 100644 index 0000000000..41f0f3c4fa --- /dev/null +++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/pom.xml @@ -0,0 +1,46 @@ + + 4.0.0 + + io.sarl.pythongenerator + io.sarl.pythongenerator + 0.6.0-SNAPSHOT + + + io.sarl.pythongenerator.plugin + eclipse-plugin + Python Generator Plugin + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + src + + + + + + + + + + + default-profile + + true + + + + + org.eclipse.tycho + tycho-source-plugin + + + + + + + diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/PyExecutableExtensionFactory.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/PyExecutableExtensionFactory.java new file mode 100644 index 0000000000..180e757b5a --- /dev/null +++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/PyExecutableExtensionFactory.java @@ -0,0 +1,42 @@ +/* + * $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; + +import org.osgi.framework.Bundle; + +import io.sarl.lang.ui.SARLExecutableExtensionFactory; + +/** Factory for injecting SARL instances. + * + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + */ +public class PyExecutableExtensionFactory extends SARLExecutableExtensionFactory { + + @Override + protected Bundle getBundle() { + return PyGeneratorPlugin.getDefault().getBundle(); + } + +} diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/PyGeneratorPlugin.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/PyGeneratorPlugin.java new file mode 100644 index 0000000000..d6b5ec4c33 --- /dev/null +++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/PyGeneratorPlugin.java @@ -0,0 +1,133 @@ +/* + * $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; + +import com.google.common.base.Strings; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.plugin.AbstractUIPlugin; + +/** + * Utility functions for the plugin. + * + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + */ +public class PyGeneratorPlugin extends AbstractUIPlugin { + + /** Identifier of the plugin. + */ + public static final String PLUGIN_ID = "io.sarl.pythongenerator.plugin"; //$NON-NLS-1$ + + private static PyGeneratorPlugin instance; + + /** Construct an Eclipse plugin for SARL. + */ + public PyGeneratorPlugin() { + setDefault(this); + } + + /** Set the default instance of the plugin. + * + * @param defaultInstance - the default plugin instance. + */ + public static void setDefault(PyGeneratorPlugin defaultInstance) { + instance = defaultInstance; + } + + /** Replies the instance of the plugin. + * + * @return the default plugin instance. + */ + public static PyGeneratorPlugin getDefault() { + return instance; + } + + /** + * Returns a section in the SARL Eclipse plugin's dialog settings. + * If the section doesn't exist yet, it is created. + * + * @param name - the name of the section + * @return the section of the given name + */ + public IDialogSettings getDialogSettingsSection(String name) { + final IDialogSettings dialogSettings = getDialogSettings(); + IDialogSettings section = dialogSettings.getSection(name); + if (section == null) { + section = dialogSettings.addNewSection(name); + } + return section; + } + + /** Replies the image stored in the current Eclipse plugin. + * + * @param imagePath - path of the image. + * @return the image. + */ + public Image getImage(String imagePath) { + final ImageDescriptor descriptor = getImageDescriptor(imagePath); + if (descriptor == null) { + return null; + } + return descriptor.createImage(); + } + + /** Replies the image descriptor for the given image path. + * + * @param imagePath - path of the image. + * @return the image descriptor. + */ + public ImageDescriptor getImageDescriptor(String imagePath) { + ImageDescriptor descriptor = getImageRegistry().getDescriptor(imagePath); + if (descriptor == null) { + descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, imagePath); + if (descriptor != null) { + getImageRegistry().put(imagePath, descriptor); + } + } + return descriptor; + } + + /** Create a status. + * + * @param severity - the severity level, see {@link IStatus}. + * @param cause - the cause of the problem. + * @return the status. + */ + @SuppressWarnings("static-method") + public IStatus createStatus(int severity, Throwable cause) { + String message = cause.getLocalizedMessage(); + if (Strings.isNullOrEmpty(message)) { + message = cause.getMessage(); + } + if (Strings.isNullOrEmpty(message)) { + message = cause.getClass().getSimpleName(); + } + return new Status(severity, PLUGIN_ID, message, cause); + } + +} diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/configuration/PyOutputConfigurationProvider.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/configuration/PyOutputConfigurationProvider.java new file mode 100644 index 0000000000..4fc00ffaa7 --- /dev/null +++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/configuration/PyOutputConfigurationProvider.java @@ -0,0 +1,71 @@ +/* + * $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.configuration; + +import static com.google.common.collect.Sets.newHashSet; + +import java.util.Set; + +import com.google.inject.Singleton; +import org.eclipse.xtext.generator.IOutputConfigurationProvider; +import org.eclipse.xtext.generator.OutputConfiguration; + +import io.sarl.lang.generator.extra.ExtraLanguageOutputConfigurations; +import io.sarl.pythongenerator.PyGeneratorPlugin; +import io.sarl.pythongenerator.generator.Messages; + + +/** 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 PyOutputConfigurationProvider implements IOutputConfigurationProvider { + + /** Name of the output configuration for Python 3 generator. + */ + public static final String OUTPUT_CONFIGURATION_NAME = + ExtraLanguageOutputConfigurations.createOutputConfigurationName(PyGeneratorPlugin.PLUGIN_ID); + + /** Name of the output folder in which the Python 3 files are generated. + */ + public static final String OUTPUT_FOLDER = "target/generated-sources/python3"; //$NON-NLS-1$ + + @Override + public Set getOutputConfigurations() { + final OutputConfiguration pythonOutput = new OutputConfiguration(OUTPUT_CONFIGURATION_NAME); + pythonOutput.setDescription(Messages.PyOutputConfigurationProvider_0); + pythonOutput.setOutputDirectory(OUTPUT_FOLDER); + pythonOutput.setOverrideExistingResources(true); + pythonOutput.setCreateOutputDirectory(true); + pythonOutput.setCanClearOutputDirectory(true); + pythonOutput.setCleanUpDerivedResources(true); + pythonOutput.setSetDerivedProperty(true); + pythonOutput.setKeepLocalHistory(false); + return newHashSet(pythonOutput); + } + +} diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/configuration/PyPreferenceInitializer.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/configuration/PyPreferenceInitializer.java new file mode 100644 index 0000000000..385c678840 --- /dev/null +++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/configuration/PyPreferenceInitializer.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.pythongenerator.configuration; + +import com.google.inject.Singleton; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreAccess; +import org.eclipse.xtext.ui.editor.preferences.IPreferenceStoreInitializer; + +import io.sarl.lang.generator.extra.IExtraLanguageConversionInitializer; +import io.sarl.lang.ui.generator.extra.preferences.ExtraLanguagePreferenceAccess; +import io.sarl.pythongenerator.PyGeneratorPlugin; +import io.sarl.pythongenerator.generator.PyInitializers; + + +/** Initializer for the generator's preferences. + * + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + * @since 0.6 + */ +@Singleton +public class PyPreferenceInitializer implements IPreferenceStoreInitializer { + + @Override + public void initialize(IPreferenceStoreAccess access) { + final IPreferenceStore store = access.getWritablePreferenceStore(); + initializeEnable(store); + initializeTypeConversion(store); + initializeFeatureNameConversion(store); + } + + private static void initializeEnable(IPreferenceStore store) { + final String key = ExtraLanguagePreferenceAccess.getPrefixedKey(PyGeneratorPlugin.PLUGIN_ID, + ExtraLanguagePreferenceAccess.ENABLED_PROPERTY); + store.setDefault(key, false); + } + + private static void initializeTypeConversion(IPreferenceStore store) { + final IExtraLanguageConversionInitializer tcInitializer = PyInitializers.getTypeConverterInitializer(); + final String preferenceValue = ExtraLanguagePreferenceAccess.toConverterPreferenceValue(tcInitializer); + final String key = ExtraLanguagePreferenceAccess.getPrefixedKey(PyGeneratorPlugin.PLUGIN_ID, + ExtraLanguagePreferenceAccess.TYPE_CONVERSION_PROPERTY); + store.setDefault(key, preferenceValue); + } + + private static void initializeFeatureNameConversion(IPreferenceStore store) { + final IExtraLanguageConversionInitializer fnInitializer = PyInitializers.getFeatureNameConverterInitializer(); + final String preferenceValue = ExtraLanguagePreferenceAccess.toConverterPreferenceValue(fnInitializer); + final String key = ExtraLanguagePreferenceAccess.getPrefixedKey(PyGeneratorPlugin.PLUGIN_ID, + ExtraLanguagePreferenceAccess.FEATURE_NAME_CONVERSION_PROPERTY); + store.setDefault(key, preferenceValue); + } + +} diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/Messages.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/Messages.java new file mode 100644 index 0000000000..19ea829f8e --- /dev/null +++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/Messages.java @@ -0,0 +1,49 @@ +/* + * $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 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 PyOutputConfigurationProvider_0; + + public static String PyExpressionGenerator_0; + + 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/generator/PyAppendable.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/PyAppendable.java new file mode 100644 index 0000000000..18f192e63d --- /dev/null +++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/PyAppendable.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.generator; + +import io.sarl.lang.generator.extra.ExtraLanguageAppendable; +import io.sarl.lang.generator.extra.ExtraLanguageImportManager; +import io.sarl.lang.generator.extra.ExtraLanguageTypeConverter; + +/** Appendable dedicated to Python. + * + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + * @since 0.6 + */ +public class PyAppendable extends ExtraLanguageAppendable { + + private static final String INDENTATION = "\t"; //$NON-NLS-1$ + + private static final String LINE_SEPARATOR = "\n"; //$NON-NLS-1$ + + private static final char INNER_TYPE_SEPARATOR = '.'; + + /** Constructor. + * + * @param converter the type converter. + */ + public PyAppendable(ExtraLanguageTypeConverter converter) { + super(INDENTATION, LINE_SEPARATOR, + new ExtraLanguageImportManager(converter, INNER_TYPE_SEPARATOR)); + } + +} diff --git a/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/PyExpressionGenerator.java b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/PyExpressionGenerator.java new file mode 100644 index 0000000000..a6ceca0c3b --- /dev/null +++ b/contribs/io.sarl.pythongenerator/io.sarl.pythongenerator.plugin/src/io/sarl/pythongenerator/generator/PyExpressionGenerator.java @@ -0,0 +1,1008 @@ +/* + * $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.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.xtend.core.xtend.AnonymousClass; +import org.eclipse.xtext.EcoreUtil2; +import org.eclipse.xtext.common.types.JvmFormalParameter; +import org.eclipse.xtext.common.types.JvmIdentifiableElement; +import org.eclipse.xtext.common.types.JvmType; +import org.eclipse.xtext.common.types.JvmTypeReference; +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 org.eclipse.xtext.xbase.lib.Functions.Function0; +import org.eclipse.xtext.xbase.typesystem.references.FunctionTypeReference; +import org.eclipse.xtext.xbase.typesystem.references.LightweightTypeReference; + +import io.sarl.lang.generator.extra.AbstractExpressionGenerator; +import io.sarl.lang.generator.extra.IExtraLanguageConversionInitializer; +import io.sarl.lang.generator.extra.IExtraLanguageGeneratorContext; +import io.sarl.lang.generator.extra.IRootGenerator; +import io.sarl.lang.sarl.SarlBreakExpression; +import io.sarl.pythongenerator.PyGeneratorPlugin; + +/** Generator of XExpression for Python 3. + * + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + * @since 0.6 + */ +@SuppressWarnings("checkstyle:classfanoutcomplexity") +public class PyExpressionGenerator extends AbstractExpressionGenerator { + + @Override + protected String getGeneratorPluginID() { + return PyGeneratorPlugin.PLUGIN_ID; + } + + @Override + protected IExtraLanguageConversionInitializer getTypeConverterInitializer() { + return PyInitializers.getTypeConverterInitializer(); + } + + @Override + protected IExtraLanguageConversionInitializer getFeatureNameConverterInitializer() { + return PyInitializers.getFeatureNameConverterInitializer(); + } + + private static void appendReturnIfExpectedReturnedExpression(IAppendable it, IExtraLanguageGeneratorContext context) { + if (context.getExpectedExpressionType() != null) { + it.append("return "); //$NON-NLS-1$ + } + } + + @Override + protected void before(XExpression expression, IAppendable output, IExtraLanguageGeneratorContext context) { + if (!(expression instanceof XClosure) && !(expression instanceof AnonymousClass)) { + // Generate the closure definitions before their usage in the expressions + for (final XClosure closure : EcoreUtil2.getAllContentsOfType(expression, XClosure.class)) { + generateClosureDefinition(closure, output, context); + } + // Generate the closure definitions before their usage in the expressions + for (final AnonymousClass anonClass : EcoreUtil2.getAllContentsOfType(expression, AnonymousClass.class)) { + generateAnonymousClassDefinition(anonClass, output, context); + } + } + } + + /** Generate the closure definition. + * + * @param closure the closure. + * @param it the target for the generated content. + * @param context the context. + */ + protected void generateClosureDefinition(XClosure closure, IAppendable it, IExtraLanguageGeneratorContext context) { + if (!it.hasName(closure)) { + final String closureName = it.declareSyntheticVariable(closure, "__closure"); //$NON-NLS-1$ + it.openPseudoScope(); + it.append("def ").append(closureName).append("(self"); //$NON-NLS-1$//$NON-NLS-2$ + for (final JvmFormalParameter param : closure.getFormalParameters()) { + it.append(", "); //$NON-NLS-1$ + final String name = it.declareUniqueNameVariable(param, param.getName()); + it.append(name); + } + it.append("):"); //$NON-NLS-1$ + it.increaseIndentation().newLine(); + if (closure.getExpression() != null) { + LightweightTypeReference type = getExpectedType(closure); + if (type.isFunctionType()) { + final FunctionTypeReference fctRef = type.tryConvertToFunctionTypeReference(true); + if (fctRef != null) { + type = fctRef.getReturnType(); + } else { + type = null; + } + } else { + type = null; + } + //LightweightTypeReference returnType = getClosureOperationReturnType(type, operation); + generate(closure.getExpression(), type, it, context); + } else { + it.append("pass"); //$NON-NLS-1$ + } + it.decreaseIndentation().newLine(); + it.closeScope(); + } + } + + /** Generate the anonymous class definition. + * + * @param anonClass the anonymous class. + * @param it the target for the generated content. + * @param context the context. + */ + protected void generateAnonymousClassDefinition(AnonymousClass anonClass, IAppendable it, IExtraLanguageGeneratorContext context) { + if (!it.hasName(anonClass) && it instanceof PyAppendable) { + final String anonClassName = it.declareSyntheticVariable(anonClass, "AnonClass"); //$NON-NLS-1$ + anonClass.setName(anonClassName); + it.openPseudoScope(); + final IRootGenerator rootGenerator = context.getRootGenerator(); + if (rootGenerator instanceof PyGenerator) { + final List types = new ArrayList<>(); + for (final JvmTypeReference superType : anonClass.getConstructorCall().getConstructor().getDeclaringType().getSuperTypes()) { + if (!Object.class.getCanonicalName().equals(superType.getIdentifier())) { + types.add(superType); + } + } + // Add the object type because of an issue in the Python language. + final JvmTypeReference objType = getTypeReferences().getTypeForName(Object.class, anonClass); + types.add(objType); + ((PyGenerator) rootGenerator).generateTypeDeclaration( + anonClassName, + false, + types, + false, + anonClass.getMembers(), + (PyAppendable) it, + context, + null); + } + it.closeScope(); + } + } + + /** Generate the given object. + * + * @param anonClass the anonymous class. + * @param it the target for the generated content. + * @param context the context. + * @return the class definition. + */ + @SuppressWarnings("static-method") + protected XExpression _generate(AnonymousClass anonClass, IAppendable it, IExtraLanguageGeneratorContext context) { + if (it.hasName(anonClass)) { + appendReturnIfExpectedReturnedExpression(it, context); + it.append(it.getName(anonClass)); + } + return anonClass; + } + + /** Generate the given object. + * + * @param closure the closure. + * @param it the target for the generated content. + * @param context the context. + * @return the closure. + */ + @SuppressWarnings("static-method") + protected XExpression _generate(XClosure closure, IAppendable it, IExtraLanguageGeneratorContext context) { + if (it.hasName(closure)) { + appendReturnIfExpectedReturnedExpression(it, context); + it.append(it.getName(closure)); + } + return closure; + } + + /** Generate the given object. + * + * @param block the block expression. + * @param it the target for the generated content. + * @param context the context. + * @return the last expression in the block or {@code null}. + */ + protected XExpression _generate(XBlockExpression block, IAppendable it, IExtraLanguageGeneratorContext context) { + XExpression last = block; + if (block.getExpressions().isEmpty()) { + it.append("pass"); //$NON-NLS-1$ + } else { + it.openScope(); + if (context.getExpectedExpressionType() == null) { + boolean first = true; + for (final XExpression expression : block.getExpressions()) { + if (first) { + first = false; + } else { + it.newLine(); + } + last = generate(expression, it, context); + } + } else { + final List exprs = block.getExpressions(); + if (!exprs.isEmpty()) { + for (int i = 0; i < exprs.size() - 1; ++i) { + if (i > 0) { + it.newLine(); + } + last = generate(exprs.get(i), it, context); + } + last = generate(exprs.get(exprs.size() - 1), context.getExpectedExpressionType(), it, context); + } + } + it.closeScope(); + } + return last; + } + + /** Generate the given object. + * + * @param literal the literal. + * @param it the target for the generated content. + * @param context the context. + * @return the literal. + */ + @SuppressWarnings("static-method") + protected XExpression _generate(XNumberLiteral literal, IAppendable it, IExtraLanguageGeneratorContext context) { + appendReturnIfExpectedReturnedExpression(it, context); + it.append(literal.getValue()); + return literal; + } + + /** Generate the given object. + * + * @param literal the literal. + * @param it the target for the generated content. + * @param context the context. + * @return the literal. + */ + @SuppressWarnings("static-method") + protected XExpression _generate(XStringLiteral literal, IAppendable it, IExtraLanguageGeneratorContext context) { + appendReturnIfExpectedReturnedExpression(it, context); + it.append("u\"").append(Strings.convertToJavaString(literal.getValue())).append("\""); //$NON-NLS-1$//$NON-NLS-2$ + return literal; + } + + /** Generate the given object. + * + * @param breakStatement the break statement. + * @param it the target for the generated content. + * @param context the context. + * @return the statement. + */ + @SuppressWarnings("static-method") + protected XExpression _generate(SarlBreakExpression breakStatement, IAppendable it, IExtraLanguageGeneratorContext context) { + if (context.getExpectedExpressionType() == null) { + it.append("break"); //$NON-NLS-1$ + } else { + it.append("return ").append(toDefaultValue(context.getExpectedExpressionType().toJavaCompliantTypeReference())); //$NON-NLS-1$ + } + return breakStatement; + } + + /** Generate the given object. + * + * @param assignment the assignment operator. + * @param it the target for the generated content. + * @param context the context. + * @return the assignment. + */ + protected XExpression _generate(XAssignment assignment, IAppendable it, IExtraLanguageGeneratorContext context) { + appendReturnIfExpectedReturnedExpression(it, context); + newFeatureCallGenerator(context, it).generate(assignment); + it.append(" = "); //$NON-NLS-1$ + generate(assignment.getValue(), it, context); + return assignment; + } + + /** Generate the given object. + * + * @param operation the binary operation. + * @param it the target for the generated content. + * @param context the context. + * @return the operation. + */ + @SuppressWarnings("checkstyle:cyclomaticcomplexity") + protected XExpression _generate(XBinaryOperation operation, IAppendable it, IExtraLanguageGeneratorContext context) { + appendReturnIfExpectedReturnedExpression(it, context); + final String operator = getOperatorSymbol(operation); + if (operator != null) { + generate(operation.getLeftOperand(), it, context); + switch (operator) { + case "-": //$NON-NLS-1$ + case "+": //$NON-NLS-1$ + case "*": //$NON-NLS-1$ + case "/": //$NON-NLS-1$ + case "%": //$NON-NLS-1$ + case "-=": //$NON-NLS-1$ + case "+=": //$NON-NLS-1$ + case "*=": //$NON-NLS-1$ + case "/=": //$NON-NLS-1$ + case "%=": //$NON-NLS-1$ + case "<": //$NON-NLS-1$ + case ">": //$NON-NLS-1$ + case "<=": //$NON-NLS-1$ + case ">=": //$NON-NLS-1$ + case "==": //$NON-NLS-1$ + case "!=": //$NON-NLS-1$ + case "<<": //$NON-NLS-1$ + case ">>": //$NON-NLS-1$ + it.append(" ").append(operator).append(" "); //$NON-NLS-1$ //$NON-NLS-2$ + break; + case "&&": //$NON-NLS-1$ + it.append(" and "); //$NON-NLS-1$ + break; + case "||": //$NON-NLS-1$ + it.append(" or "); //$NON-NLS-1$ + break; + case "===": //$NON-NLS-1$ + it.append(" is "); //$NON-NLS-1$ + break; + case "!==": //$NON-NLS-1$ + it.append(" is not "); //$NON-NLS-1$ + break; + default: + throw new IllegalArgumentException(MessageFormat.format(Messages.PyExpressionGenerator_0, operator)); + } + generate(operation.getRightOperand(), it, context); + } + return operation; + } + + /** Generate the given object. + * + * @param call the feature call. + * @param it the target for the generated content. + * @param context the context. + * @return the feature call. + */ + protected XExpression _generate(XFeatureCall call, IAppendable it, IExtraLanguageGeneratorContext context) { + appendReturnIfExpectedReturnedExpression(it, context); + newFeatureCallGenerator(context, it).generate(call); + return call; + } + + /** Generate the given object. + * + * @param call the member feature call. + * @param it the target for the generated content. + * @param context the context. + * @return the feature call. + */ + protected XExpression _generate(XMemberFeatureCall call, IAppendable it, IExtraLanguageGeneratorContext context) { + appendReturnIfExpectedReturnedExpression(it, context); + newFeatureCallGenerator(context, it).generate(call); + return call; + } + + /** Generate the given object. + * + * @param operation the postfix operator. + * @param it the target for the generated content. + * @param context the context. + * @return the operation. + */ + protected XExpression _generate(XPostfixOperation operation, IAppendable it, IExtraLanguageGeneratorContext context) { + appendReturnIfExpectedReturnedExpression(it, context); + final String operator = getOperatorSymbol(operation); + if (operator != null) { + switch (operator) { + case "++": //$NON-NLS-1$ + generate(operation.getOperand(), it, context); + it.append(" += 1"); //$NON-NLS-1$ + break; + case "--": //$NON-NLS-1$ + generate(operation.getOperand(), it, context); + it.append(" -= 1"); //$NON-NLS-1$ + break; + default: + throw new IllegalArgumentException(MessageFormat.format(Messages.PyExpressionGenerator_0, operator)); + } + } + return operation; + } + + /** Generate the given object. + * + * @param operation the unary operation. + * @param it the target for the generated content. + * @param context the context. + * @return the operation. + */ + protected XExpression _generate(XUnaryOperation operation, IAppendable it, IExtraLanguageGeneratorContext context) { + appendReturnIfExpectedReturnedExpression(it, context); + final String operator = getOperatorSymbol(operation); + if (operator != null) { + switch (operator) { + case "+": //$NON-NLS-1$ + generate(operation.getOperand(), it, context); + break; + case "-": //$NON-NLS-1$ + it.append("-"); //$NON-NLS-1$ + generate(operation.getOperand(), it, context); + break; + default: + throw new IllegalArgumentException(MessageFormat.format(Messages.PyExpressionGenerator_0, operator)); + } + } + return operation; + } + + /** Generate the given object. + * + * @param call the constructor call. + * @param it the target for the generated content. + * @param context the context. + * @return the constructor call. + */ + protected XExpression _generate(XConstructorCall call, IAppendable it, IExtraLanguageGeneratorContext context) { + appendReturnIfExpectedReturnedExpression(it, context); + newFeatureCallGenerator(context, it).generate(call); + return call; + } + + /** Generate the given object. + * + * @param whileLoop the while-loop. + * @param it the target for the generated content. + * @param context the context. + * @return the last statement in the loop or {@code null}. + */ + protected XExpression _generate(XWhileExpression whileLoop, IAppendable it, IExtraLanguageGeneratorContext context) { + it.append("while "); //$NON-NLS-1$ + generate(whileLoop.getPredicate(), it, context); + it.append(":"); //$NON-NLS-1$ + it.increaseIndentation().newLine(); + final XExpression last = generate(whileLoop.getBody(), it, context); + it.decreaseIndentation(); + return last; + } + + /** Generate the given object. + * + * @param whileLoop the while-loop. + * @param it the target for the generated content. + * @param context the context. + * @return the last statement in the loop or {@code null}. + */ + protected XExpression _generate(XDoWhileExpression whileLoop, IAppendable it, IExtraLanguageGeneratorContext context) { + generate(whileLoop.getBody(), it, context); + it.newLine(); + it.append("while "); //$NON-NLS-1$ + generate(whileLoop.getPredicate(), it, context); + it.append(":"); //$NON-NLS-1$ + it.increaseIndentation().newLine(); + final XExpression last = generate(whileLoop.getBody(), it, context); + it.decreaseIndentation(); + return last; + } + + /** Generate the given object. + * + * @param forLoop the for-loop. + * @param it the target for the generated content. + * @param context the context. + * @return the statement. + */ + protected XExpression _generate(XForLoopExpression forLoop, IAppendable it, IExtraLanguageGeneratorContext context) { + it.append("for "); //$NON-NLS-1$ + final String varName = it.declareUniqueNameVariable(forLoop.getDeclaredParam(), forLoop.getDeclaredParam().getSimpleName()); + it.append(varName); + it.append(" in "); //$NON-NLS-1$ + generate(forLoop.getForExpression(), it, context); + it.append(":"); //$NON-NLS-1$ + it.increaseIndentation().newLine(); + final XExpression last = generate(forLoop.getEachExpression(), it, context); + it.decreaseIndentation(); + return last; + } + + /** Generate the given object. + * + * @param forLoop the for-loop. + * @param it the target for the generated content. + * @param context the context. + * @return the last statement in the loop or {@code null}. + */ + protected XExpression _generate(XBasicForLoopExpression forLoop, IAppendable it, IExtraLanguageGeneratorContext context) { + for (final XExpression expr : forLoop.getInitExpressions()) { + generate(expr, it, context); + it.newLine(); + } + it.append("while "); //$NON-NLS-1$ + generate(forLoop.getExpression(), it, context); + it.append(":"); //$NON-NLS-1$ + it.increaseIndentation().newLine(); + final XExpression last = generate(forLoop.getEachExpression(), it, context); + for (final XExpression expr : forLoop.getUpdateExpressions()) { + it.newLine(); + generate(expr, it, context); + } + it.decreaseIndentation(); + return last; + } + + /** Generate the given object. + * + * @param literal the boolean literal. + * @param it the target for the generated content. + * @param context the context. + * @return the literal. + */ + @SuppressWarnings("static-method") + protected XExpression _generate(XBooleanLiteral literal, IAppendable it, IExtraLanguageGeneratorContext context) { + appendReturnIfExpectedReturnedExpression(it, context); + it.append(literal.isIsTrue() ? "True" : "False"); //$NON-NLS-1$ //$NON-NLS-2$ + return literal; + } + + /** Generate the given object. + * + * @param castOperator the cast operator. + * @param it the target for the generated content. + * @param context the context. + * @return the expression. + */ + protected XExpression _generate(XCastedExpression castOperator, IAppendable it, IExtraLanguageGeneratorContext context) { + return generate(castOperator.getTarget(), context.getExpectedExpressionType(), it, context); + } + + /** Generate the given object. + * + * @param literal the list literal. + * @param it the target for the generated content. + * @param context the context. + * @return the literal. + */ + protected XExpression _generate(XListLiteral literal, IAppendable it, IExtraLanguageGeneratorContext context) { + appendReturnIfExpectedReturnedExpression(it, context); + it.append("["); //$NON-NLS-1$ + boolean first = true; + for (final XExpression value : literal.getElements()) { + if (first) { + first = false; + } else { + it.append(", "); //$NON-NLS-1$ + } + generate(value, it, context); + } + it.append("]"); //$NON-NLS-1$ + return literal; + } + + /** Generate the given object. + * + * @param literal the set literal. + * @param it the target for the generated content. + * @param context the context. + * @return the literal. + */ + protected XExpression _generate(XSetLiteral literal, IAppendable it, IExtraLanguageGeneratorContext context) { + appendReturnIfExpectedReturnedExpression(it, context); + it.append("{"); //$NON-NLS-1$ + boolean first = true; + for (final XExpression value : literal.getElements()) { + if (first) { + first = false; + } else { + it.append(", "); //$NON-NLS-1$ + } + generate(value, it, context); + } + it.append("}"); //$NON-NLS-1$ + return literal; + } + + /** Generate the given object. + * + * @param ifStatement the if-then-else statement. + * @param it the target for the generated content. + * @param context the context. + * @return the statement. + */ + protected XExpression _generate(XIfExpression ifStatement, IAppendable it, IExtraLanguageGeneratorContext context) { + it.append("if "); //$NON-NLS-1$ + generate(ifStatement.getIf(), it, context); + it.append(":"); //$NON-NLS-1$ + it.increaseIndentation().newLine(); + if (ifStatement.getThen() != null) { + generate(ifStatement.getThen(), context.getExpectedExpressionType(), it, context); + } else if (context.getExpectedExpressionType() == null) { + it.append("pass"); //$NON-NLS-1$ + } else { + it.append("return ").append(toDefaultValue(context.getExpectedExpressionType().toJavaCompliantTypeReference())); //$NON-NLS-1$ + } + it.decreaseIndentation(); + if (ifStatement.getElse() != null) { + it.newLine().append("else:"); //$NON-NLS-1$ + it.increaseIndentation().newLine(); + generate(ifStatement.getElse(), context.getExpectedExpressionType(), it, context); + it.decreaseIndentation(); + } else if (context.getExpectedExpressionType() != null) { + it.newLine().append("else:"); //$NON-NLS-1$ + it.increaseIndentation().newLine(); + it.append("return ").append(toDefaultValue(context.getExpectedExpressionType().toJavaCompliantTypeReference())); //$NON-NLS-1$ + it.decreaseIndentation(); + } + return ifStatement; + } + + + /** Generate the given object. + * + * @param operator the instance-of operator. + * @param it the target for the generated content. + * @param context the context. + * @return the expression. + */ + protected XExpression _generate(XInstanceOfExpression operator, IAppendable it, IExtraLanguageGeneratorContext context) { + appendReturnIfExpectedReturnedExpression(it, context); + it.append("isinstance("); //$NON-NLS-1$ + generate(operator.getExpression(), it, context); + it.append(", "); //$NON-NLS-1$ + it.append(operator.getType().getType()); + it.append(")"); //$NON-NLS-1$ + return operator; + } + + + /** Generate the given object. + * + * @param literal the null literal. + * @param it the target for the generated content. + * @param context the context. + * @return the literal. + */ + @SuppressWarnings("static-method") + protected XExpression _generate(XNullLiteral literal, IAppendable it, IExtraLanguageGeneratorContext context) { + appendReturnIfExpectedReturnedExpression(it, context); + it.append("None"); //$NON-NLS-1$ + return literal; + } + + /** Generate the given object. + * + * @param returnStatement the return statement. + * @param it the target for the generated content. + * @param context the context. + * @return the statement. + */ + protected XExpression _generate(XReturnExpression returnStatement, IAppendable it, IExtraLanguageGeneratorContext context) { + it.append("return "); //$NON-NLS-1$ + generate(returnStatement.getExpression(), it, context); + return returnStatement; + } + + /** Generate the given object. + * + * @param switchStatement the switch statement. + * @param it the target for the generated content. + * @param context the context. + * @return the statement. + */ + @SuppressWarnings({ "checkstyle:npathcomplexity", "checkstyle:cyclomaticcomplexity" }) + protected XExpression _generate(XSwitchExpression switchStatement, IAppendable it, IExtraLanguageGeneratorContext context) { + final String varName; + if (switchStatement.getDeclaredParam() != null) { + varName = it.declareUniqueNameVariable(switchStatement.getDeclaredParam(), + switchStatement.getDeclaredParam().getSimpleName()); + } else { + varName = it.declareSyntheticVariable(switchStatement, "___expression"); //$NON-NLS-1$ + } + it.openPseudoScope(); + it.append(varName).append(" = "); //$NON-NLS-1$ + generate(switchStatement.getSwitch(), it, context); + it.newLine(); + boolean first = true; + boolean fallThrough = false; + for (final XCasePart caseExpression : switchStatement.getCases()) { + if (fallThrough) { + it.append(") or ("); //$NON-NLS-1$ + } else if (first) { + it.append("if ("); //$NON-NLS-1$ + first = false; + } else { + it.append("elif ("); //$NON-NLS-1$ + } + if (caseExpression.getTypeGuard() != null) { + it.append("isinstance(").append(varName); //$NON-NLS-1$ + it.append(", ").append(caseExpression.getTypeGuard().getType()); //$NON-NLS-1$ + it.append(")"); //$NON-NLS-1$ + if (caseExpression.getCase() != null) { + it.append(" and ("); //$NON-NLS-1$ + generate(caseExpression.getCase(), it, context); + it.append(")"); //$NON-NLS-1$ + final LightweightTypeReference convertedType = getExpectedType(caseExpression.getCase()); + if (!convertedType.isType(Boolean.TYPE) && !convertedType.isType(Boolean.class)) { + it.append(" == ").append(varName); //$NON-NLS-1$ + } + } + } else if (caseExpression.getCase() != null) { + it.append("("); //$NON-NLS-1$ + generate(caseExpression.getCase(), it, context); + it.append(")"); //$NON-NLS-1$ + final LightweightTypeReference convertedType = getExpectedType(caseExpression.getCase()); + if (!convertedType.isType(Boolean.TYPE) && !convertedType.isType(Boolean.class)) { + it.append(" == ").append(varName); //$NON-NLS-1$ + } + } + fallThrough = caseExpression.isFallThrough(); + if (!fallThrough) { + it.append("):"); //$NON-NLS-1$ + it.increaseIndentation().newLine(); + if (caseExpression.getThen() != null) { + generate(caseExpression.getThen(), it, context); + } else { + it.append("pass"); //$NON-NLS-1$ + } + it.decreaseIndentation().newLine(); + } + } + if (switchStatement.getDefault() != null) { + if (first) { + generate(switchStatement.getDefault(), it, context); + it.newLine(); + } else { + it.append("else:"); //$NON-NLS-1$ + it.increaseIndentation().newLine(); + generate(switchStatement.getDefault(), it, context); + it.decreaseIndentation().newLine(); + } + } + it.closeScope(); + return switchStatement; + } + + /** Generate the given object. + * + * @param synchronizedStatement the synchronized statement. + * @param it the target for the generated content. + * @param context the context. + * @return the statement. + */ + protected XExpression _generate(XSynchronizedExpression synchronizedStatement, IAppendable it, IExtraLanguageGeneratorContext context) { + return generate(synchronizedStatement.getExpression(), context.getExpectedExpressionType(), it, context); + } + + /** Generate the given object. + * + * @param throwStatement the throw statement. + * @param it the target for the generated content. + * @param context the context. + * @return the statement. + */ + protected XExpression _generate(XThrowExpression throwStatement, IAppendable it, IExtraLanguageGeneratorContext context) { + it.append("raise "); //$NON-NLS-1$ + generate(throwStatement.getExpression(), it, context); + return throwStatement; + } + + /** Generate the given object. + * + * @param tryStatement the try-catch-finally statement. + * @param it the target for the generated content. + * @param context the context. + * @return the statement. + */ + protected XExpression _generate(XTryCatchFinallyExpression tryStatement, IAppendable it, IExtraLanguageGeneratorContext context) { + it.append("try:"); //$NON-NLS-1$ + it.increaseIndentation().newLine(); + generate(tryStatement.getExpression(), context.getExpectedExpressionType(), it, context); + it.decreaseIndentation().newLine(); + for (final XCatchClause clause : tryStatement.getCatchClauses()) { + it.append("except "); //$NON-NLS-1$ + it.append(clause.getDeclaredParam().getParameterType().getType()); + it.append(", "); //$NON-NLS-1$ + it.append(it.declareUniqueNameVariable(clause.getDeclaredParam(), clause.getDeclaredParam().getSimpleName())); + it.append(":"); //$NON-NLS-1$ + it.increaseIndentation().newLine(); + generate(clause.getExpression(), context.getExpectedExpressionType(), it, context); + it.decreaseIndentation().newLine(); + } + if (tryStatement.getFinallyExpression() != null) { + it.append("finally:"); //$NON-NLS-1$ + it.increaseIndentation().newLine(); + generate(tryStatement.getFinallyExpression(), it, context); + it.decreaseIndentation(); + } + return tryStatement; + } + + /** Generate the given object. + * + * @param literal the type literal. + * @param it the target for the generated content. + * @param context the context. + * @return the literal. + */ + @SuppressWarnings("static-method") + protected XExpression _generate(XTypeLiteral literal, IAppendable it, IExtraLanguageGeneratorContext context) { + appendReturnIfExpectedReturnedExpression(it, context); + it.append(literal.getType()); + return literal; + } + + /** Generate the given object. + * + * @param varDeclaration the variable declaration. + * @param it the target for the generated content. + * @param context the context. + * @return the statement. + */ + protected XExpression _generate(XVariableDeclaration varDeclaration, IAppendable it, IExtraLanguageGeneratorContext context) { + final String name = it.declareUniqueNameVariable(varDeclaration, varDeclaration.getName()); + it.append(name); + it.append(" = "); //$NON-NLS-1$ + if (varDeclaration.getRight() != null) { + generate(varDeclaration.getRight(), it, context); + } else if (varDeclaration.getType() != null) { + it.append(toDefaultValue(varDeclaration.getType())); + } else { + it.append("None"); //$NON-NLS-1$ + } + if (context.getExpectedExpressionType() != null) { + it.newLine(); + it.append("return ").append(name); //$NON-NLS-1$ + } + return varDeclaration; + } + + /** Replies the Python default value for the given type. + * + * @param type the type. + * @return the default value. + */ + @SuppressWarnings({"checkstyle:cyclomaticcomplexity", "checkstyle:booleanexpressioncomplexity" }) + public static String toDefaultValue(JvmTypeReference type) { + final String id = type.getIdentifier(); + if (!"void".equals(id)) { //$NON-NLS-1$ + if (Strings.equal(Boolean.class.getName(), id) || Strings.equal(Boolean.TYPE.getName(), id)) { + return "False"; //$NON-NLS-1$ + } + if (Strings.equal(Float.class.getName(), id) || Strings.equal(Float.TYPE.getName(), id) + || Strings.equal(Double.class.getName(), id) || Strings.equal(Double.TYPE.getName(), id)) { + return "0.0"; //$NON-NLS-1$ + } + if (Strings.equal(Integer.class.getName(), id) || Strings.equal(Integer.TYPE.getName(), id) + || Strings.equal(Long.class.getName(), id) || Strings.equal(Long.TYPE.getName(), id) + || Strings.equal(Byte.class.getName(), id) || Strings.equal(Byte.TYPE.getName(), id) + || Strings.equal(Short.class.getName(), id) || Strings.equal(Short.TYPE.getName(), id)) { + return "0"; //$NON-NLS-1$ + } + if (Strings.equal(Character.class.getName(), id) || Strings.equal(Character.TYPE.getName(), id)) { + return "\"\\0\""; //$NON-NLS-1$ + } + } + return "None"; //$NON-NLS-1$ + } + + /** Generate a feature call. + * + * @param context the generation context. + * @param it the code receiver. + * @return the generator + */ + protected PyFeatureCallGenerator newFeatureCallGenerator(IExtraLanguageGeneratorContext context, IAppendable it) { + return new PyFeatureCallGenerator(context, it); + } + + /** Feature call generator for Python. + * + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + * @since 0.6 + */ + public class PyFeatureCallGenerator extends FeatureCallGenerator { + + /** Constructor. + * @param context the generation context. + * @param codeReceiver the code receiver. + */ + protected PyFeatureCallGenerator(IExtraLanguageGeneratorContext context, IAppendable codeReceiver) { + super(context, codeReceiver); + } + + private void appendCallPrefix(Collection elements, String postfix) { + if (elements != null && !elements.isEmpty()) { + boolean first = true; + for (final Object element : elements) { + if (first) { + first = false; + } else { + this.codeReceiver.append("."); //$NON-NLS-1$ + } + if (element instanceof XExpression) { + PyExpressionGenerator.this.generate((XExpression) element, this.codeReceiver, this.context); + } else if (element instanceof JvmType) { + this.codeReceiver.append((JvmType) element); + } else if (element instanceof LightweightTypeReference) { + this.codeReceiver.append((LightweightTypeReference) element); + } else { + this.codeReceiver.append(element.toString()); + } + } + this.codeReceiver.append(postfix); + } + } + + @Override + protected void appendCall(JvmIdentifiableElement calledFeature, List leftOperand, + List receiver, String name, + List args, Function0 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 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 superTypes, boolean ignoreObjectType, List 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 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 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 bindBuilderConfigurationBlock() { + return Issue282BuilderConfigurationBlock.class; + } + + public Class bindIOutputConfigurationProvider() { + return ExtensionPointExtraLanguageOutputConfigurationProvider.class; + } + + public Class bindIGenerator() { + return ExtraLanguageSupportGenerator.class; + } + + @SingletonBinding(eager = true) + public Class bindSARLValidator() { + return Bug621SARLExtraLanguageValidator.class; + } + + public Class bindIExtraLanguageGeneratorProvider() { + return ExtensionPointExtraLanguageGeneratorProvider.class; + } + + public Class bindIExtraLanguageValidatorProvider() { + return ExtensionPointExtraLanguageValidatorProvider.class; + } + + public Class bindTypeConverterRuleReader() { + return PreferenceBasedTypeConverterRuleReader.class; + } + + public Class 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 bindIQualifiedNameConverter() { return Bug356QualifiedNameConverter.class; } - @Override - @SingletonBinding(eager = true) - public Class bindSARLValidator() { - return Bug621SARLValidator.class; - } - @Override public Class bindDefaultReentrantTypeResolver() { return Bug623SARLReentrantTypeResolver.class; } @Override - public Class bindIGenerator() { - return ExtraLanguageGenerator.class; + @SingletonBinding(eager = true) + public Class 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 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 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 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 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 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 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 typeErrorHandler, + Function2 featureErrorHandler) { + final ExtraLanguageFeatureNameConverter converter = getFeatureNameConverter(); + if (converter != null) { + final ConversionType conversionType = converter.getConversionTypeFor(featureCall); + switch (conversionType) { + case EXPLICIT: + return true; + case IMPLICIT: + final JvmIdentifiableElement element = featureCall.getFeature(); + if (element instanceof JvmType) { + return doTypeMappingCheck(featureCall, (JvmType) element, typeErrorHandler); + } + if (featureCall instanceof XMemberFeatureCall) { + final XMemberFeatureCall memberFeatureCall = (XMemberFeatureCall) featureCall; + final XExpression receiver = memberFeatureCall.getMemberCallTarget(); + if (receiver instanceof XMemberFeatureCall || receiver instanceof XFeatureCall) { + internalCheckMemberFeaturCallMapping( + (XAbstractFeatureCall) receiver, + typeErrorHandler, + featureErrorHandler); + } + } + break; + case FORBIDDEN_CONVERSION: + default: + if (featureErrorHandler != null) { + return !featureErrorHandler.apply(featureCall, featureCall.getFeature()); + } + return false; + } + } + return true; + } + + /** Comparator of feature calls. + * + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + * @since 0.6 + */ + private static final class FeatureCallComparator implements Comparator { + + public static final FeatureCallComparator SINGLETON = new FeatureCallComparator(); + + private FeatureCallComparator() { + // + } + + @Override + public int compare(XAbstractFeatureCall o1, XAbstractFeatureCall o2) { + assert o1 != null && o2 != null; + if (o1 == o2) { + return 0; + } + return Integer.compare(System.identityHashCode(o1), System.identityHashCode(o2)); + } + } + +} diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/extra/ExtraLanguageSupportValidator.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/extra/ExtraLanguageSupportValidator.java new file mode 100644 index 0000000000..e8eaba5b88 --- /dev/null +++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/extra/ExtraLanguageSupportValidator.java @@ -0,0 +1,101 @@ +/* + * $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.logging.Level; +import java.util.logging.Logger; + +import com.google.inject.Inject; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EValidator; +import org.eclipse.xtext.validation.Check; +import org.eclipse.xtext.validation.CheckType; + +import io.sarl.lang.validation.SARLValidator; + +/** The generator from SARL to the default target language and an extra target language. + * + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + * @since 0.6 + */ +public class ExtraLanguageSupportValidator extends SARLValidator { + + private IExtraLanguageValidatorProvider extraValidatorProvider; + + private Logger logger; + + /** Change the logger. + * + * @param logger the logger. + */ + @Inject + public void setLogger(Logger logger) { + this.logger = logger; + } + + /** Replies the logger. + * + * @return the logger. + */ + public Logger getLogger() { + return this.logger; + } + + /** Change the provider of the extra validator. + * + * @param provider the provider. + */ + @Inject + public void setExtraGeneratorProvider(IExtraLanguageValidatorProvider provider) { + this.extraValidatorProvider = provider; + } + + /** Replies the provider of the extra validators. + * + * @return the provider. + */ + public IExtraLanguageValidatorProvider getExtraValidatorProvider() { + return this.extraValidatorProvider; + } + + /** Launch the validation for the extra languages. + * + * @param object the object to check + */ + @Check(CheckType.EXPENSIVE) + public void extraLanguageValidation(EObject object) { + final Iterable validators = getExtraValidatorProvider().getValidators(object.eResource()); + if (validators != null) { + for (final EValidator validator : validators) { + try { + validator.validate(object, getChain(), getContext()); + } catch (Throwable exception) { + getLogger().log(Level.SEVERE, exception.getLocalizedMessage(), exception); + } + } + } + } + +} diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/extra/IExtraLanguageValidatorProvider.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/extra/IExtraLanguageValidatorProvider.java new file mode 100644 index 0000000000..c1e5c59543 --- /dev/null +++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/extra/IExtraLanguageValidatorProvider.java @@ -0,0 +1,48 @@ +/* + * $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 com.google.inject.ImplementedBy; +import org.eclipse.emf.ecore.EValidator; +import org.eclipse.emf.ecore.resource.Resource; + +/** Provider of the extra language validators. + * + *

The validators will be used to validate the SARL program for extra-language. + * + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + * @since 0.6 + */ +@ImplementedBy(NullExtraLanguageValidatorProvider.class) +public interface IExtraLanguageValidatorProvider { + + /** Replies the validators that should be used for validating the SARL program for the extra language. + * + * @param resource the resource for which the validators should be retreived. + * @return the list of the generators. + */ + Iterable getValidators(Resource resource); + +} diff --git a/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/extra/NullExtraLanguageValidatorProvider.java b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/extra/NullExtraLanguageValidatorProvider.java new file mode 100644 index 0000000000..d0a13634ff --- /dev/null +++ b/main/coreplugins/io.sarl.lang/src/io/sarl/lang/validation/extra/NullExtraLanguageValidatorProvider.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.lang.validation.extra; + +import java.util.Collections; + +import org.eclipse.emf.ecore.EValidator; +import org.eclipse.emf.ecore.resource.Resource; + +/** Implementation of the provider of the extra language validators that replies no generator. + * + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + * @since 0.6 + */ +public class NullExtraLanguageValidatorProvider implements IExtraLanguageValidatorProvider { + + @Override + public Iterable getValidators(Resource resource) { + return Collections.emptyList(); + } + +} diff --git a/main/coreplugins/io.sarl.m2e/src/io/sarl/m2e/Messages.java b/main/coreplugins/io.sarl.m2e/src/io/sarl/m2e/Messages.java index 707c978602..866ed0bb6a 100644 --- a/main/coreplugins/io.sarl.m2e/src/io/sarl/m2e/Messages.java +++ b/main/coreplugins/io.sarl.m2e/src/io/sarl/m2e/Messages.java @@ -32,7 +32,7 @@ */ @SuppressWarnings("all") public class Messages extends NLS { - private static final String BUNDLE_NAME = "io.sarl.m2e.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/features/io.sarl.baseplatform/feature.xml b/main/features/io.sarl.baseplatform/feature.xml index 800d1c061b..1442413724 100644 --- a/main/features/io.sarl.baseplatform/feature.xml +++ b/main/features/io.sarl.baseplatform/feature.xml @@ -297,6 +297,7 @@ + @@ -613,14 +614,7 @@ id="com.google.guava" download-size="0" install-size="0" - version="19.0.0" - unpack="false"/> - - diff --git a/main/features/io.sarl.lib/feature.xml b/main/features/io.sarl.lib/feature.xml index a8668516ae..e01cd68cda 100644 --- a/main/features/io.sarl.lib/feature.xml +++ b/main/features/io.sarl.lib/feature.xml @@ -253,7 +253,7 @@ id="com.google.guava" download-size="0" install-size="0" - version="0.0.0" + version="18.0.0" unpack="false"/> + diff --git a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/Messages.java b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/Messages.java index c92a005866..d92c19bcce 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/Messages.java +++ b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/Messages.java @@ -32,7 +32,7 @@ */ @SuppressWarnings("all") public class Messages extends NLS { - private static final String BUNDLE_NAME = "io.janusproject.messages"; //$NON-NLS-1$ + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ public static String Boot_0; public static String Boot_1; public static String Boot_10; diff --git a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/eclipse/buildpath/Messages.java b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/eclipse/buildpath/Messages.java index 989b0b4f6b..10bd03e8f9 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/eclipse/buildpath/Messages.java +++ b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/eclipse/buildpath/Messages.java @@ -32,7 +32,7 @@ */ @SuppressWarnings("all") public class Messages extends NLS { - private static final String BUNDLE_NAME = "io.janusproject.eclipse.buildpath.messages"; //$NON-NLS-1$ + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ public static String JanusClasspathContainer_0; public static String JanusClasspathContainerInitializer_0; public static String JanusContainerWizardPage_0; diff --git a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/eclipse/sre/Messages.java b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/eclipse/sre/Messages.java index 84760913b8..99536ad078 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/eclipse/sre/Messages.java +++ b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/eclipse/sre/Messages.java @@ -32,7 +32,7 @@ */ @SuppressWarnings("all") public class Messages extends NLS { - private static final String BUNDLE_NAME = "io.janusproject.eclipse.sre.messages"; //$NON-NLS-1$ + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ public static String JanusSREInstall_0; static { // initialize resource bundle diff --git a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/Messages.java b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/Messages.java index 3d5d15999c..4b3c94d693 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/Messages.java +++ b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/Messages.java @@ -32,7 +32,7 @@ */ @SuppressWarnings("all") public class Messages extends NLS { - private static final String BUNDLE_NAME = "io.janusproject.kernel.messages"; //$NON-NLS-1$ + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ public static String Kernel_0; public static String Kernel_1; static { diff --git a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/bic/Messages.java b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/bic/Messages.java index 86c490888b..3e063c8d66 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/bic/Messages.java +++ b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/bic/Messages.java @@ -32,7 +32,7 @@ */ @SuppressWarnings("all") public class Messages extends NLS { - private static final String BUNDLE_NAME = "io.janusproject.kernel.bic.messages"; //$NON-NLS-1$ + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ public static String ExternalContextAccessSkill_0; public static String ExternalContextAccessSkill_1; public static String InternalEventBusSkill_0; diff --git a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/gson/Messages.java b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/gson/Messages.java index 73d96d43f8..e1083bf9a9 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/gson/Messages.java +++ b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/gson/Messages.java @@ -32,7 +32,7 @@ */ @SuppressWarnings("all") public class Messages extends NLS { - private static final String BUNDLE_NAME = "io.janusproject.kernel.services.gson.messages"; //$NON-NLS-1$ + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ public static String GsonEventSerializer_0; static { // initialize resource bundle diff --git a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/hazelcast/Messages.java b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/hazelcast/Messages.java index 4a2f090fff..1f8f2b6352 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/hazelcast/Messages.java +++ b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/hazelcast/Messages.java @@ -32,7 +32,7 @@ */ @SuppressWarnings("all") public class Messages extends NLS { - private static final String BUNDLE_NAME = "io.janusproject.kernel.services.hazelcast.messages"; //$NON-NLS-1$ + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ public static String HazelcastKernelDiscoveryService_0; public static String HazelcastKernelDiscoveryService_1; static { diff --git a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/jdk/contextspace/Messages.java b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/jdk/contextspace/Messages.java index 0dde82e323..9a24956942 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/jdk/contextspace/Messages.java +++ b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/jdk/contextspace/Messages.java @@ -31,7 +31,7 @@ */ @SuppressWarnings("all") public class Messages extends NLS { - private static final String BUNDLE_NAME = "io.janusproject.kernel.services.jdk.contextspace.messages"; //$NON-NLS-1$ + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ public static String Context_0; public static String Context_1; public static String StandardContextSpaceService_0; diff --git a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/jdk/executors/Messages.java b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/jdk/executors/Messages.java index d5f0c3a6f2..157bcaa0b4 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/jdk/executors/Messages.java +++ b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/jdk/executors/Messages.java @@ -32,7 +32,7 @@ */ @SuppressWarnings("all") public class Messages extends NLS { - private static final String BUNDLE_NAME = "io.janusproject.kernel.services.jdk.executors.messages"; //$NON-NLS-1$ + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ public static String JdkRejectedExecutionHandler_0; public static String JdkUncaughtExceptionHandler_0; public static String JdkUncaughtExceptionHandler_1; diff --git a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/jdk/network/Messages.java b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/jdk/network/Messages.java index 4fe35f6ca1..84d7523c9f 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/jdk/network/Messages.java +++ b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/jdk/network/Messages.java @@ -32,7 +32,7 @@ */ @SuppressWarnings("all") public class Messages extends NLS { - private static final String BUNDLE_NAME = "io.janusproject.kernel.services.jdk.network.messages"; //$NON-NLS-1$ + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ public static String AESEventEncrypter_0; public static String JavaBinaryEventSerializer_0; static { diff --git a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/jdk/spawn/Messages.java b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/jdk/spawn/Messages.java index d92752ec2f..0205534bcf 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/jdk/spawn/Messages.java +++ b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/jdk/spawn/Messages.java @@ -32,7 +32,7 @@ */ @SuppressWarnings("all") public class Messages extends NLS { - private static final String BUNDLE_NAME = "io.janusproject.kernel.services.jdk.spawn.messages"; //$NON-NLS-1$ + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ public static String StandardSpawnService_0; public static String StandardSpawnService_1; public static String StandardSpawnService_2; diff --git a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/zeromq/Messages.java b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/zeromq/Messages.java index 714021213b..7d6642ef8b 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/zeromq/Messages.java +++ b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/services/zeromq/Messages.java @@ -31,7 +31,7 @@ */ @SuppressWarnings("all") public class Messages extends NLS { - private static final String BUNDLE_NAME = "io.janusproject.kernel.services.zeromq.messages"; //$NON-NLS-1$ + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ public static String ZeroMQNetworkService_0; public static String ZeroMQNetworkService_1; public static String ZeroMQNetworkService_10; diff --git a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/space/Messages.java b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/space/Messages.java index 2c5a7cf3e1..a7a478b118 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/space/Messages.java +++ b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/kernel/space/Messages.java @@ -32,7 +32,7 @@ */ @SuppressWarnings("all") public class Messages extends NLS { - private static final String BUNDLE_NAME = "io.janusproject.kernel.space.messages"; //$NON-NLS-1$ + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ public static String AbstractEventSpace_0; public static String AbstractEventSpace_1; static { diff --git a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/modules/hazelcast/Messages.java b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/modules/hazelcast/Messages.java index 3226d17f1a..7c58d06a62 100644 --- a/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/modules/hazelcast/Messages.java +++ b/sre/io.janusproject/io.janusproject.plugin/src/io/janusproject/modules/hazelcast/Messages.java @@ -32,7 +32,7 @@ */ @SuppressWarnings("all") public class Messages extends NLS { - private static final String BUNDLE_NAME = "io.janusproject.modules.hazelcast.messages"; //$NON-NLS-1$ + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ public static String SpaceIDSerializer_0; public static String SpaceIDSerializer_1; static { diff --git a/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to00399/Bug23.java b/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to00399/Bug23.java index 745ddeb7c6..528d44477a 100644 --- a/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to00399/Bug23.java +++ b/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/bugs/to00399/Bug23.java @@ -26,7 +26,7 @@ import io.sarl.tests.api.AbstractSarlTest; /** - * @author $Author: srodriguez$ + * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ diff --git a/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/modules/extralang/ExtraLanguagecompilerTest.java b/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/modules/extralang/ExtraLanguagecompilerTest.java deleted file mode 100644 index c421627e25..0000000000 --- a/tests/io.sarl.lang.tests/src/test/java/io/sarl/lang/tests/modules/extralang/ExtraLanguagecompilerTest.java +++ /dev/null @@ -1,101 +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.tests.modules.extralang; - -import java.io.File; - -import javax.inject.Inject; -import javax.inject.Provider; - -import org.apache.log4j.Level; -import org.eclipse.xtext.xbase.testing.CompilationTestHelper; -import org.junit.Test; - -import io.sarl.lang.SARLVersion; -import io.sarl.lang.compiler.batch.SarlBatchCompiler; -import io.sarl.lang.sarl.SarlPackage; -import io.sarl.tests.api.AbstractSarlTest; - - -/** - * @author $Author: sgalland$ - * @version $FullVersion$ - * @mavengroupid $GroupId$ - * @mavenartifactid $ArtifactId$ - */ -@SuppressWarnings("all") -public class ExtraLanguagecompilerTest extends AbstractSarlTest { - - @Inject - private CompilationTestHelper compiler; - - @Test - public void variable() throws Exception { - String source = "class C1 { var v = 45 }"; - String expected = multilineString( - "import io.sarl.lang.annotation.SarlElementType;", - "import io.sarl.lang.annotation.SarlSpecification;", - "import io.sarl.lang.annotation.SyntheticMember;", - "import org.eclipse.xtext.xbase.lib.Pure;", - "", - "@SarlSpecification(\"" + SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING + "\")", - "@SarlElementType(" + SarlPackage.SARL_CLASS + ")", - "@SuppressWarnings(\"all\")", - "public class C1 {", - " private int v = 45;", - " ", - " @Override", - " @Pure", - " @SyntheticMember", - " public boolean equals(final Object obj) {", - " if (this == obj)", - " return true;", - " if (obj == null)", - " return false;", - " if (getClass() != obj.getClass())", - " return false;", - " C1 other = (C1) obj;", - " if (other.v != this.v)", - " return false;", - " return super.equals(obj);", - " }", - " ", - " @Override", - " @Pure", - " @SyntheticMember", - " public int hashCode() {", - " int result = super.hashCode();", - " final int prime = 31;", - " result = prime * result + this.v;", - " return result;", - " }", - " ", - " @SyntheticMember", - " public C1() {", - " super();", - " }", - "}", - "" - ); - this.compiler.assertCompilesTo(source, expected); - } - -} diff --git a/tests/io.sarl.tests.api/src/main/java/io/sarl/tests/api/AbstractExtraLanguageGeneratorTest.java b/tests/io.sarl.tests.api/src/main/java/io/sarl/tests/api/AbstractExtraLanguageGeneratorTest.java new file mode 100644 index 0000000000..07f0b07b36 --- /dev/null +++ b/tests/io.sarl.tests.api/src/main/java/io/sarl/tests/api/AbstractExtraLanguageGeneratorTest.java @@ -0,0 +1,114 @@ +/* + * $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.tests.api; + +import java.io.IOException; +import java.util.Map; + +import javax.inject.Inject; + +import org.eclipse.xtext.generator.IFileSystemAccess; +import org.eclipse.xtext.generator.IOutputConfigurationProvider; +import org.eclipse.xtext.generator.OutputConfiguration; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.util.Strings; +import org.eclipse.xtext.xbase.testing.CompilationTestHelper; +import org.eclipse.xtext.xbase.testing.CompilationTestHelper.Result; +import org.junit.ComparisonFailure; + + +/** Abstract implementation for testing extra language generators. + * + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + * @since 0.6 + */ +@SuppressWarnings("all") +@InjectWith(ExtendedSARLInjectorProvider.class) +public abstract class AbstractExtraLanguageGeneratorTest extends AbstractSarlTest { + + @Inject + private CompilationTestHelper compiler; + + @Inject + private IOutputConfigurationProvider outputConfigurationProvider; + + protected abstract String getOutputConfigurationName(); + + protected OutputConfiguration getOutputConfiguration() { + Iterable configurations = this.outputConfigurationProvider.getOutputConfigurations(); + OutputConfiguration defaultConfiguration = null; + for (final OutputConfiguration configuration : configurations) { + if (Strings.equal(IFileSystemAccess.DEFAULT_OUTPUT, configuration.getName())) { + defaultConfiguration = configuration; + } else if (Strings.equal(getOutputConfigurationName(), configuration.getName())) { + return configuration; + } + } + return defaultConfiguration; + } + + protected GeneratorTest compile(String source) throws IOException { + final Result[] result = new Result[1]; + this.compiler.compile(source, (it) -> { + result[0] = it; + }); + return new GeneratorTest(result[0]); + } + + /** Generator test API. + * + * @author $Author: sgalland$ + * @version $FullVersion$ + * @mavengroupid $GroupId$ + * @mavenartifactid $ArtifactId$ + */ + public class GeneratorTest { + + private final Result result; + + GeneratorTest(Result result) { + this.result = result; + } + + public void assertTypeDefinition(String typeName, String expectedContent) { + final OutputConfiguration configuration = getOutputConfiguration(); + if (configuration == null) { + throw new ComparisonFailure("", expectedContent, ""); + } + final String filename = typeName.replaceAll("\\.", "/") + ".py"; + final String key = "/" + CompilationTestHelper.PROJECT_NAME + "/" + configuration.getOutputDirectory() + "/" + filename; + final Map generatedResources = this.result.getAllGeneratedResources(); + CharSequence ocontent = generatedResources.get(key); + final String content; + if (ocontent == null) { + content = ""; + } else { + content = ocontent.toString(); + } + assertEquals(expectedContent, ocontent); + } + + } + +}