001/*-------------------------------------------------------------------------+ 002| | 003| Copyright 2005-2011 The ConQAT Project | 004| | 005| Licensed under the Apache License, Version 2.0 (the "License"); | 006| you may not use this file except in compliance with the License. | 007| You may obtain a copy of the License at | 008| | 009| http://www.apache.org/licenses/LICENSE-2.0 | 010| | 011| Unless required by applicable law or agreed to in writing, software | 012| distributed under the License is distributed on an "AS IS" BASIS, | 013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 014| See the License for the specific language governing permissions and | 015| limitations under the License. | 016+-------------------------------------------------------------------------*/ 017package eu.cqse.check.framework.scanner; 018 019import java.io.File; 020import java.util.Collections; 021import java.util.EnumSet; 022import java.util.HashSet; 023import java.util.List; 024import java.util.Set; 025 026import org.conqat.lib.commons.collections.CollectionUtils; 027import org.conqat.lib.commons.collections.ListMap; 028import org.conqat.lib.commons.filesystem.FileSystemUtils; 029import org.conqat.lib.commons.js_export.ExportToJavaScript; 030import org.conqat.lib.commons.resources.Resource; 031 032/** 033 * Enumeration class for the languages support by the scanner framework. 034 * 035 * <strong>This class is used for communication with IDE clients (via the 036 * {@link org.conqat.engine.service.shared.client.IdeServiceClient}), so special 037 * care has to be taken when changing its signature!</strong> 038 */ 039@ExportToJavaScript 040public enum ELanguage { 041 042 // we need to use the ugly workaround with asHashSet here as we cannot use 043 // varargs twice in the constructor 044 045 /** Java */ 046 JAVA("Java", true, "java"), 047 048 /** C/C++ */ 049 CPP("C/C++", true, "cpp", "cc", "c", "h", "hh", "hpp", "cxx", "hxx", "inl", "inc", "pc"), 050 051 /** OpenCL C/C++ */ 052 OPEN_CL("OpenCL C/C++", true, "cl"), 053 054 /** Rust */ 055 RUST("Rust", true, "rs"), 056 057 /** Visual Basic */ 058 VB("Visual Basic", false, "vb", "frm", "cls", "bas"), 059 060 /** PL/I */ 061 PL1("PL/I", false, "pl1", "pli"), 062 063 /** COBOL */ 064 COBOL("COBOL", false, "cbl", "cob", "cobol", "cpy", "eco"), 065 066 /** C# */ 067 CS("C#", true, "cs"), 068 069 /** ABAP */ 070 ABAP("ABAP", false, "abap"), 071 072 /** 073 * ABAP Dictionary. This is a textual representation of objects in the ABAP 074 * Dictionary (aka DDIC). The format is based on the textual format for 075 * structure and database table definition which is available starting with SAP 076 * ABP Platform v7.51 or v7.52 respectively. See 077 * <a>https://help.sap.com/doc/abapdocu_752_index_htm/7.52/de-DE/abenddic_tools.htm</a>. 078 * This format is again based on the SAP CDS DDL 079 * <a>https://help.sap.com/doc/abapdocu_752_index_htm/7.52/de-DE/abencds_f1_ddl_syntax.htm</a>. 080 * If available, we export ABAP DDIC objects in the textual representation as 081 * provided by the SAP system, otherwise our Teamscale Connector for the SAP 082 * ABAP Platform serializes the text in a similar format. 083 */ 084 ABAP_DDIC("ABAP Dictionary", false, "abap_ddic"), 085 086 /** Ada */ 087 ADA("Ada", false, "ada", "ads", "adb"), 088 089 /** Natural language text */ 090 TEXT("Plain Text", false, "txt"), 091 092 /** XML */ 093 XML("XML", true, "xml", "xsl", "xslt", "architecture", "cqb", "csproj", "config"), 094 095 /** HANA SQLScript */ 096 SQLSCRIPT("HANA SQLScript", false, "sql", "hdbprocedure", "hdbfunction", "hdbscalarfunction", "hdbtablefunction"), 097 098 /** 099 * HANA Views XML. This includes view specifications which of SAP HANA database 100 * which are stored in XML. Does NOT include HANA code which is not XML (e.g. 101 * *.hdbview) 102 */ 103 HANA_VIEW("HANA View", true, "analyticview", "attributeview", "calculationview"), 104 105 /** PL/SQL */ 106 PLSQL("PL/SQL", false, "sql", "pks", "pkb", "trg", "fnc", "typ", "tyb", "prc", "plsql"), 107 108 /** Python */ 109 PYTHON("Python", true, "py"), 110 111 /** T-SQL aka Transact SQL. */ 112 TSQL("Transact-SQL", false, "tsql"), 113 114 /** Matlab */ 115 MATLAB("Matlab", true, "m"), 116 117 /** PHP */ 118 PHP("PHP", true, "php", "php3", "php4", "php5"), 119 120 /** Ruby */ 121 RUBY("Ruby", true, "rb"), 122 123 /** 124 * JavaScript including EcmaScript and TypeScript. 125 * <p> 126 * Note that the statement oracle only works if semicolons are used 127 * consistently. However, semicolons are optional in JavaScript (rules described 128 * here: http://bclary.com/2004/11/07/#a-7.9), but to determine end of statement 129 * in this case requires a full blown parser (hard to decide locally in some 130 * cases). As most coding guidelines recommend using semicolons anyway, we stick 131 * with this solution. 132 */ 133 JAVASCRIPT("JavaScript/TypeScript", true, "js", "sj", "ts", "tsx"), 134 135 /** The language used within the M/Text printing system. */ 136 MTEXT("M/TEXT", true, "mtx"), 137 138 /** 139 * The "Just Your Average Computer Company Procedural Language". A C-like 140 * language being part of the Panther framework developed by the company 141 * Prolifics. The language is used in the archive system d.3 developed by the 142 * company "d.velop". 143 */ 144 JPL("JPL", true, "jpl"), 145 146 /** 147 * Use this for languages for which no dedicated scanner is available. Creates a 148 * token per line (and creates EOL tokens). 149 */ 150 LINE("Line-based Text", false), 151 152 /** Delphi */ 153 DELPHI("Delphi", false, "pas", "dpr"), 154 155 /** 156 * IEC 61131-3 Structured Text. We understand both the code (PU) and variable 157 * structure (SV). 158 * <ul> 159 * <li>.pou files contain program code (written in ST language)</li> 160 * <li>.dt files contain type declarations (written in ST language)</li> 161 * </ul> 162 * Sadly, the file endings and format are not standardized in IEC-61131-3. 163 */ 164 IEC61131("IEC 61131-3 ST", true, "pu", "sv", "st", "scl", "pou", "dt", "var"), 165 166 /** Fortran */ 167 FORTRAN("Fortran", false, "f", "for", "f77", "f90", "f95", "f03"), 168 169 /** Xtend */ 170 XTEND("Xtend", true, "xtend"), 171 172 /** Swift */ 173 SWIFT("Swift", true, "swift"), 174 175 /** OCaml */ 176 OCAML("OCaml", true, "ml", "mli"), 177 178 /** Opentext Oscript */ 179 OSCRIPT("OScript", true, "osx", "lxe", "os"), 180 181 /** Groovy */ 182 GROOVY("Groovy", true, "groovy"), 183 184 /** Requirement documents. */ 185 NL_REQUIREMENTS("Natural Language Requirements", false), 186 187 /** Requirement documents. */ 188 NL_TESTS("Natural Language Tests", false), 189 190 /** Simulink and Stateflow. */ 191 SIMULINK("Simulink and Stateflow", false, "mdl", "slx", "sldd"), 192 193 /** Gosu (https://gosu-lang.github.io/). */ 194 GOSU("Gosu", true, "gsp", "gs", "gsx", "gr", "grs"), 195 196 /** Kotlin. */ 197 KOTLIN("Kotlin", true, "kt", "kts", "ktm"), 198 199 /** Objective C. */ 200 OBJECTIVE_C("Objective-C", true, "m", "h"), 201 202 /** JavaDoc */ 203 JAVADOC("JavaDoc", true), 204 205 /** Go */ 206 GO("Go", true, "go"); 207 208 /** List of languages that do not have methods. */ 209 private static final EnumSet<ELanguage> LANGUAGES_WITHOUT_METHODS = EnumSet.of(ABAP_DDIC, LINE, NL_REQUIREMENTS, 210 NL_TESTS, TEXT, XML, HANA_VIEW); 211 212 /** This maps from extensions to languages. */ 213 private static final ListMap<String, ELanguage> EXTENSION_2_LANGUAGE_MAP = new ListMap<>(); 214 215 /** Initialize {@link #EXTENSION_2_LANGUAGE_MAP}. */ 216 static { 217 for (ELanguage language : values()) { 218 for (String extension : language.extensions) { 219 EXTENSION_2_LANGUAGE_MAP.add(extension.toLowerCase(), language); 220 } 221 } 222 } 223 224 /** The readable name of the language, to be used, e.g., in a UI. */ 225 private final String readableName; 226 227 /** Whether the language is case sensitive. */ 228 private final boolean caseSensitive; 229 230 /** File extensions commonly used for this language. */ 231 private final String[] extensions; 232 233 /** Create language. */ 234 ELanguage(String readableName, boolean caseSensitive, String... extensions) { 235 this.readableName = readableName; 236 this.caseSensitive = caseSensitive; 237 this.extensions = extensions; 238 } 239 240 /** Returns {@link #readableName}. */ 241 public String getReadableName() { 242 return readableName; 243 } 244 245 /** Return whether the language is case sensitive. */ 246 public boolean isCaseSensitive() { 247 return caseSensitive; 248 } 249 250 /** Get the file extensions commonly used for this language. */ 251 public String[] getFileExtensions() { 252 return CollectionUtils.copyArray(extensions); 253 } 254 255 /** 256 * Gets the {@link ELanguage} value corresponding to the extension of the 257 * resource. Returns null if no extension was found. If there are multiple 258 * possible languages, the first one is returned. 259 */ 260 public static ELanguage fromResource(Resource resource) { 261 return fromFileExtension(resource.getExtension()); 262 } 263 264 /** 265 * Gets the {@link ELanguage} value corresponding to the file extension of the 266 * path. Returns null if no extension was found. If there are multiple possible 267 * languages, the first one is returned. This method should only be used for 268 * test code or as a fallback since file extensions may match multiple 269 * {@link ELanguage}s. 270 */ 271 public static ELanguage fromPath(String path) { 272 return fromFile(new File(path)); 273 } 274 275 /** 276 * Gets the {@link ELanguage} value corresponding to the file extension of the 277 * file. Returns null if no extension was found. If there are multiple possible 278 * languages, the first one is returned. This method should only be used for 279 * test code or as a fallback since file extensions may match multiple 280 * {@link ELanguage}s. 281 */ 282 public static ELanguage fromFile(File file) { 283 return fromFileExtension(FileSystemUtils.getFileExtension(file)); 284 } 285 286 /** 287 * Gets the {@link ELanguage} value corresponding to the given file extension 288 * (without a dot). Returns {@link ELanguage#LINE} as a fallback if no language 289 * was registered for the extension. If there are multiple possible languages 290 * registered for the extension, however, the first one is returned. 291 */ 292 public static ELanguage fromFileExtension(String extension) { 293 if (extension == null) { 294 return ELanguage.LINE; 295 } 296 297 List<ELanguage> result = EXTENSION_2_LANGUAGE_MAP.getCollection(extension.toLowerCase()); 298 299 if (result == null || result.isEmpty()) { 300 return ELanguage.LINE; 301 } 302 return result.get(0); 303 } 304 305 /** Returns all languages for the given file extension */ 306 public static Set<ELanguage> getAllLanguagesForExtension(String extension) { 307 if (extension == null) { 308 return Collections.emptySet(); 309 } 310 return new HashSet<>(EXTENSION_2_LANGUAGE_MAP.getCollectionOrEmpty(extension.toLowerCase())); 311 } 312 313 /** 314 * Returns all {@link ELanguage}s matching the file extension of the given file 315 * path. 316 */ 317 public static Set<ELanguage> getAllLanguagesForPath(String path) { 318 return getAllLanguagesForExtension(FileSystemUtils.getFileExtension(path)); 319 } 320 321 /** @return Whether the given language has the concept of methods. */ 322 public static boolean languageHasMethods(ELanguage language) { 323 return !LANGUAGES_WITHOUT_METHODS.contains(language); 324 } 325 326}