Files
wudsn-ide/com.wudsn.ide.asm/src/com/wudsn/ide/lng/compiler/CompilerDefinition.java
2021-09-26 22:54:47 +02:00

508 lines
16 KiB
Java

/**
* Copyright (C) 2009 - 2021 <a href="https://www.wudsn.com" target="_top">Peter Dell</a>
*
* This file is part of WUDSN IDE.
*
* WUDSN IDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* WUDSN IDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WUDSN IDE. If not, see <http://www.gnu.org/licenses/>.
*/
package com.wudsn.ide.lng.compiler;
import java.io.File;
import java.util.List;
import java.util.Locale;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import com.wudsn.ide.base.common.StringUtility;
import com.wudsn.ide.base.common.TextUtility;
import com.wudsn.ide.base.hardware.Hardware;
import com.wudsn.ide.lng.Language;
import com.wudsn.ide.lng.LanguagePlugin;
import com.wudsn.ide.lng.LanguageUtility;
import com.wudsn.ide.lng.Target;
import com.wudsn.ide.lng.Texts;
import com.wudsn.ide.lng.compiler.CompilerHelp.HelpDocument;
import com.wudsn.ide.lng.compiler.syntax.CompilerSyntax;
/**
* Definition of a compiler. The definition contains all static meta information
* about the compiler. It is normally defined via an extension. The id of a
* compiler must be unique across all compilers.
*
* @author Peter Dell
*/
public final class CompilerDefinition implements Comparable<CompilerDefinition> {
// Language
private Language language;
// Id
private String id;
private String name;
private String className;
// Installation and use.
private String helpDocumentPaths;
private String homePageURL;
// Editing and source parsing.
private List<Target> supportedTargets;
private CompilerSyntax syntax;
// Compiling.
private String defaultParameters;
// Assignment to default hardware type.
private Hardware defaultHardware;
/**
* Creation is package local. Called by {@link CompilerRegistry} only.
*/
CompilerDefinition() {
}
/**
* Gets the key that uniquely identifies a compiler. They key has the format
* "<language>/<id>".
*
* @return The key that uniquely identifies the compiler, not <code>null</code>.
*/
public static String getKey(Language language, String id) {
if (language == null) {
throw new IllegalStateException("Field 'language' must not be null for this or for argument.");
}
if (id == null) {
throw new IllegalStateException("Field 'id' must not be null for this or for argument.");
}
return language.name() + "/" + id;
}
/**
* Gets the key that uniquely identifies the compiler. They key has the format
* "<language>/<id>".
*
* @return The key that uniquely identifies the compiler, not <code>null</code>.
*/
public String getKey() {
return getKey(language, id);
}
/**
* Sets the language of the compiler. Called by {@link CompilerRegistry} only.
*
* @param language The language of the compiler, not empty and not
* <code>null</code>.
*/
final void setLanguage(String language) {
if (language == null) {
throw new IllegalArgumentException("Parameter 'language' must not be null.");
}
if (StringUtility.isEmpty(language)) {
throw new IllegalArgumentException("Parameter 'language' must not be empty.");
}
this.language = Language.valueOf(language);
}
/**
* Gets the language of the compiler.
*
* @return The language of the compiler, not <code>null</code>.
*/
public final Language getLanguage() {
if (language == null) {
throw new IllegalStateException("Field 'language' must not be null.");
}
return language;
}
/**
* Sets the id of the compiler. Called by {@link CompilerRegistry} only.
*
* @param id The id of the compiler, not empty and not <code>null</code>.
*/
final void setId(String id) {
if (id == null) {
throw new IllegalArgumentException("Parameter 'id' must not be null.");
}
if (StringUtility.isEmpty(id)) {
throw new IllegalArgumentException("Parameter 'id' must not be empty.");
}
this.id = id;
}
/**
* Gets the id of the compiler.
*
* @return The id of the compiler, not empty and not <code>null</code>.
*/
public final String getId() {
if (id == null) {
throw new IllegalStateException("Field 'id' must not be null.");
}
return id;
}
/**
* Sets the localized name of the compiler. Called by {@link CompilerRegistry}
* only.
*
* @param name The localized name of the compiler, not empty and not
* <code>null</code>.
*/
final void setName(String name) {
if (name == null) {
throw new IllegalArgumentException("Parameter 'name' must not be null.");
}
if (StringUtility.isEmpty(id)) {
throw new IllegalArgumentException("Parameter 'name' must not be empty.");
}
this.name = name;
}
/**
* Gets the localized name of the compiler.
*
* @return The localized name of the compiler, not empty and not
* <code>null</code>.
*/
public final String getName() {
if (name == null) {
throw new IllegalStateException("Field 'name' must not be null.");
}
return name;
}
/**
* Sets the class name of the compiler. Called by {@link CompilerRegistry} only.
*
* @param className The class name of the compiler, not empty and not
* <code>null</code>.
*/
final void setClassName(String className) {
if (className == null) {
throw new IllegalArgumentException("Parameter 'className' must not be null.");
}
this.className = className;
}
/**
* Gets the class name of the compiler.
*
* @return The class name of the compiler, not empty and not <code>null</code>.
*/
public final String getClassName() {
if (className == null) {
throw new IllegalStateException("Field 'className' must not be null.");
}
return className;
}
/**
* Sets the absolute URL of the home page where the compiler can be downloaded.
* Called by {@link CompilerRegistry} only.
*
* @param homePageURL The absolute URL of the home page where the compiler can
* be downloaded. May be empty or <code>null</code>.
*/
final void setHomePageURL(String homePageURL) {
if (homePageURL == null) {
homePageURL = "";
}
this.homePageURL = homePageURL;
}
/**
* Gets the absolute URL of the home page where the compiler can be downloaded.
*
* @return The absolute URL of the home page where the compiler can be
* downloaded. The result may be empty or <code>null</code>.
*/
public final String getHomePageURL() {
if (homePageURL == null) {
homePageURL = "";
}
return homePageURL;
}
/**
* Sets the help file paths to locate the help file for the compiler. Called by
* {@link CompilerRegistry} only.
*
* @param helpDocumentPaths The relative file path starting with "." to locate
* the help file for the compiler based on the folder
* of the executable. ".". ".." and "/" may be used to
* specify the file path. Alternatively the path can be
* an absolute URL. A path may end with a language in
* the form "(en)". Multiple paths are separated by
* ",". May be empty or <code>null</code>.
*/
final void setHelpDocumentPaths(String helpDocumentPaths) {
if (helpDocumentPaths == null) {
helpDocumentPaths = "";
}
this.helpDocumentPaths = helpDocumentPaths;
}
/**
* Gets the help file paths to locate the help file for the compiler.
*
* @return The relative file path starting with "." to locate the help file for
* the compiler based on the folder of the executable. ".". ".." and "/"
* may be used to specify the file path. Alternatively the path can be
* an absolute URL. A path may end with a language in the form "(en)".
* Multiple paths are separated by ",". May be empty or
* <code>null</code>.
*/
public final String getHelpDocumentPaths() {
if (helpDocumentPaths == null) {
throw new IllegalStateException("Field 'helpDocumentPaths' must not be null.");
}
return helpDocumentPaths;
}
/**
* Determines if this compiler offers help at all.
*
* @return <code>true</code> if this compiler offers a help file,
* <code>false</code> otherwise.
*/
public final boolean hasHelpDocumentPaths() {
return StringUtility.isSpecified(helpDocumentPaths);
}
/**
* Gets the help file for the compiler. This includes locating the most
* appropriate file in the file system based on the current locale.
*
* @param compilerExecutablePath the compiler executable path, may be empty, not
* <code>null</code>.
* @return The help file, or <code>null</code> not help file could be found.
*
* @throws CoreException if the compilerExecutablePath is empty, the compiler
* does not specify a help path or no help file can be
* found.
*/
public final List<HelpDocument> getHelpDocuments(String compilerExecutablePath) throws CoreException {
if (compilerExecutablePath == null) {
throw new IllegalArgumentException("Parameter 'compilerExecutablePath' must not be null.");
}
String compilerText = LanguageUtility.getCompilerTextLower(language);
if (!hasHelpDocumentPaths()) {
// INFO: The {0} '{1}' does not specify help document paths.
throw new CoreException(new Status(IStatus.INFO, LanguagePlugin.ID,
TextUtility.format(Texts.MESSAGE_E102, compilerText, name)));
}
String compilerPreferencesText = LanguageUtility.getCompilerPreferencesText(language);
if (StringUtility.isEmpty(compilerExecutablePath)) {
// ERROR: Help for the '{0}' {1} cannot be displayed because the path to the
// compiler executable is not set in the {2} preferences.
throw new CoreException(new Status(IStatus.ERROR, LanguagePlugin.ID,
TextUtility.format(Texts.MESSAGE_E130, name, compilerText, compilerPreferencesText)));
}
return CompilerHelp.getHelpDocuments(helpDocumentPaths, compilerExecutablePath);
}
public final HelpDocument getHelpForCurrentLocale(String compilerExecutablePath) throws CoreException {
List<HelpDocument> helpDocuments = getHelpDocuments(compilerExecutablePath);
String localeLanguage = Locale.getDefault().getLanguage();
// Find the first existing local file and the first existing local file with
// matching language.
HelpDocument firstFile = null;
HelpDocument firstLanguageFile = null;
for (HelpDocument helpDocument : helpDocuments) {
if (helpDocument.file != null && helpDocument.file.exists()) {
if (firstFile == null) {
firstFile = helpDocument;
}
if (firstLanguageFile == null && helpDocument.language.equals(localeLanguage)) {
firstLanguageFile = helpDocument;
}
}
}
// Use language specific file if present, use first file otherwise.
HelpDocument result = firstLanguageFile;
if (result == null) {
result = firstFile;
}
// No local file specified or found. Try the URIs.
if (result == null) {
for (HelpDocument helpDocument : helpDocuments) {
if (helpDocument.uri != null) {
if (firstFile == null) {
firstFile = helpDocument;
}
if (firstLanguageFile == null && helpDocument.language.equals(localeLanguage)) {
firstLanguageFile = helpDocument;
}
}
}
// Use language specific URI if present, use first URI otherwise.
result = firstLanguageFile;
if (result == null) {
result = firstFile;
}
}
// No local file specified or found and no URIs found.
if (result == null) {
// ERROR: Help for the '{0}' {1} cannot be displayed because no help file was
// found in the paths '{2}' relative to the executable path '{3}'.
throw new CoreException(new Status(IStatus.ERROR, LanguagePlugin.ID, TextUtility.format(Texts.MESSAGE_E131,
name, LanguageUtility.getCompilerTextLower(language), helpDocumentPaths, compilerExecutablePath)));
}
return result;
}
/**
* Sets the list of supported targets. Called by {@link CompilerRegistry} only.
*
* @param supportedTargets The unmodifiable list of supported CPUs, not empty
* and not <code>null</code>.
* @since 1.6.1
*/
final void setSupportedTargets(List<Target> supportedTargets) {
if (supportedTargets == null) {
throw new IllegalArgumentException("Parameter 'supportedTargets' must not be null.");
}
if (supportedTargets.isEmpty()) {
throw new IllegalArgumentException("Parameter 'supportedTargets' must not be empty.");
}
this.supportedTargets = supportedTargets;
}
/**
* Gets the unmodifiable list of CPUs supported by this compiler. The first
* entry defines the default Target.
*
* @return The unmodifiable list of CPUs supported by this compiler, not empty
* and, not <code>null</code>.
*
* @since 1.6.1
*/
public final List<Target> getSupportedTargets() {
if (supportedTargets == null) {
throw new IllegalStateException("Field 'supportedCPUs' must not be null.");
}
return supportedTargets;
}
/**
* Sets the compiler syntax. Called by {@link CompilerRegistry} only.
*
* @param syntax The compiler syntax, not <code>null</code>.
*/
final void setSyntax(CompilerSyntax syntax) {
if (syntax == null) {
throw new IllegalArgumentException("Parameter 'syntax' must not be null.");
}
this.syntax = syntax;
}
/**
* Gets the compiler syntax.
*
* @return The compiler syntax, not <code>null</code>.
*/
public final CompilerSyntax getSyntax() {
if (syntax == null) {
throw new IllegalStateException("Field 'syntax' must not be null.");
}
return syntax;
}
/**
* Sets the compiler default parameters. Called by {@link CompilerRegistry}
* only.
*
* @param defaultParameters The compiler default parameters, not
* <code>null</code>.
*/
final void setDefaultParameters(String defaultParameters) {
if (defaultParameters == null) {
throw new IllegalArgumentException("Parameter 'defaultParameters' must not be null.");
}
this.defaultParameters = defaultParameters;
}
/**
* Gets the compiler default parameters.
*
* @return The compiler default parameters, not <code>null</code>.
*/
public final String getDefaultParameters() {
if (defaultParameters == null) {
throw new IllegalStateException("Field 'defaultParameters' must not be null.");
}
return defaultParameters;
}
/**
* Sets the default hardware to be assumed for this compiler. Called by
* {@link CompilerRegistry} only.
*
* @param hardware The default hardware, not <code>null</code>.
*/
final void setDefaultHardware(Hardware hardware) {
if (hardware == null) {
throw new IllegalArgumentException("Parameter 'hardware' must not be null.");
}
this.defaultHardware = hardware;
}
/**
* Gets the default hardware for this compiler.
*
* @return The default hardwares, not <code>null</code>.
*/
public final Hardware getDefaultHardware() {
if (defaultHardware == null) {
throw new IllegalStateException("Field 'defaultHardware' must not be null.");
}
return defaultHardware;
}
/**
* See {@link Comparable}.
*/
@Override
public int compareTo(CompilerDefinition o) {
if (o == null) {
throw new IllegalArgumentException("Parameter 'o' must not be null.");
}
return getKey().compareTo(o.getKey());
}
@Override
public String toString() {
return getKey();
}
}