├── .gitignore ├── .travis.yml ├── LICENSE.md ├── README.md ├── build.gradle ├── icons └── fileTypes │ └── jflex.png └── src └── main ├── java └── org │ └── intellij │ └── lang │ └── jflex │ ├── JFlexCommenter.java │ ├── JFlexDocumentationProvider.java │ ├── JFlexElementType.java │ ├── JFlexElementTypes.java │ ├── JFlexFindUsagesProvider.java │ ├── JFlexLanguage.java │ ├── compiler │ ├── JFlex.java │ ├── JFlexCompilerFactory.java │ ├── JFlexMessage.java │ └── JFlexSourceGeneratingCompiler.java │ ├── editor │ ├── JFlexHighlighterColors.java │ └── colors │ │ └── JFlexColorPage.java │ ├── fileTypes │ ├── JFlexFileType.java │ ├── JFlexFileTypeFactory.java │ └── JFlexSyntaxHighlighter.java │ ├── injection │ ├── EmbeddedJavaLiteralTextEscaper.java │ └── JFlexJavaInjector.java │ ├── lexer │ ├── JFlex.flex │ ├── JFlexHighlighterLexer.java │ ├── JFlexMergingLexer.java │ ├── JFlexParsingLexer.java │ └── _JFlexLexer.java │ ├── options │ ├── JFlexConfigurable.java │ ├── JFlexSettings.java │ ├── JFlexSettingsForm.form │ └── JFlexSettingsForm.java │ ├── parser │ ├── JFlexParser.java │ └── JFlexParserDefinition.java │ ├── psi │ ├── JFlexClassStatement.java │ ├── JFlexElement.java │ ├── JFlexElementVisitor.java │ ├── JFlexExpression.java │ ├── JFlexImplementsStatement.java │ ├── JFlexJavaCode.java │ ├── JFlexMacroDefinition.java │ ├── JFlexMacroReference.java │ ├── JFlexOptionStatement.java │ ├── JFlexPsiFile.java │ ├── JFlexRegexp.java │ ├── JFlexSection.java │ ├── JFlexStateDefinition.java │ ├── JFlexStateReference.java │ ├── JFlexStateStatement.java │ ├── JFlexStatement.java │ ├── JFlexTypeStatement.java │ └── impl │ │ ├── JFlexClassStatementImpl.java │ │ ├── JFlexElementImpl.java │ │ ├── JFlexExpressionImpl.java │ │ ├── JFlexImplementsStatementImpl.java │ │ ├── JFlexJavaCodeImpl.java │ │ ├── JFlexMacroDefinitionImpl.java │ │ ├── JFlexMacroReferenceImpl.java │ │ ├── JFlexOptionStatementBase.java │ │ ├── JFlexPsiFileImpl.java │ │ ├── JFlexRegexpImpl.java │ │ ├── JFlexSectionImpl.java │ │ ├── JFlexStateDefinitionImpl.java │ │ ├── JFlexStateReferenceImpl.java │ │ ├── JFlexStateStatementImpl.java │ │ ├── JFlexStatementImpl.java │ │ └── JFlexTypeStatementImpl.java │ ├── util │ ├── JFlexBundle.java │ └── JFlexBundle.properties │ └── validation │ └── JFlexAnnotatingVisitor.java └── resources └── META-INF └── plugin.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | build/ 4 | out/ 5 | gradle/ 6 | gradlew 7 | gradle.bat 8 | 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # We compile on pull requests, no need to do branches. 2 | branches: 3 | only: 4 | - master 5 | 6 | language: java 7 | 8 | jdk: 9 | - oraclejdk8 10 | 11 | 12 | script: gradle :buildPlugin 13 | 14 | # Travis sometimes fails to download deps from repo1.maven.org 15 | # A cache avoids downloading too much, and will also speed up the build. 16 | before_cache: 17 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 18 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ 19 | cache: 20 | # The timeout (in seconds) empties the cache to avoid being stuck with a corrupted artefact 21 | timeout: 86400 # 24 hours 22 | directories: 23 | - $HOME/.gradle/caches/ 24 | - $HOME/.gradle/wrapper/ 25 | - $HOME/.m2 26 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | 3 | Version 2.0, January 2004 4 | 5 | http://www.apache.org/licenses/ 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 14 | 15 | "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. 16 | 17 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 18 | 19 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 20 | 21 | "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. 22 | 23 | "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). 24 | 25 | "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. 26 | 27 | "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." 28 | 29 | "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. 30 | 31 | 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. 32 | 33 | 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. 34 | 35 | 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: 36 | 37 | You must give any other recipients of the Work or Derivative Works a copy of this License; and 38 | You must cause any modified files to carry prominent notices stating that You changed the files; and 39 | 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 40 | 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. 41 | 42 | 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. 43 | 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. 44 | 45 | 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. 46 | 47 | 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. 48 | 49 | 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. 50 | 51 | 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. 52 | 53 | END OF TERMS AND CONDITIONS 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # idea-jflex 2 | 3 | A Plugin for IntelliJ IDEA to enable JFlex support. 4 | 5 | This project was previously hosted on 6 | 7 | To build with Gradle, follow the instructions on 8 | . 9 | 10 | Import `idea-jflex` as a module using existing sources. 11 | 12 | Run the `:runide` gradle task. 13 | 14 | This plugin was tested on **IntelliJ 2018.3 EAP**. 15 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "org.jetbrains.intellij" version "0.3.10" 3 | } 4 | 5 | group 'de.jflex.ide' 6 | version 'jflex-idea-plugin' 7 | 8 | sourceCompatibility = 1.7 9 | 10 | repositories { 11 | mavenCentral() 12 | } 13 | 14 | dependencies { 15 | testCompile group: 'junit', name: 'junit', version: '4.12' 16 | } 17 | 18 | apply plugin: 'java' 19 | apply plugin: 'idea' 20 | -------------------------------------------------------------------------------- /icons/fileTypes/jflex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jflex-de/idea-jflex/d195370098177e37bd079e41bba7cb93cf040f2e/icons/fileTypes/jflex.png -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/JFlexCommenter.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex; 2 | 3 | import com.intellij.lang.Commenter; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * Created by IntelliJ IDEA. 8 | * User: Max 9 | * Date: 01.04.2008 10 | * Time: 23:39:04 11 | */ 12 | public class JFlexCommenter implements Commenter { 13 | @Nullable 14 | public String getBlockCommentPrefix() { 15 | return null; 16 | } 17 | 18 | @Nullable 19 | public String getBlockCommentSuffix() { 20 | return null; 21 | } 22 | 23 | @Nullable 24 | public String getLineCommentPrefix() { 25 | return "//"; 26 | } 27 | 28 | public String getCommentedBlockCommentSuffix() { 29 | return null; 30 | } 31 | 32 | public String getCommentedBlockCommentPrefix() { 33 | return null; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/JFlexDocumentationProvider.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.lang.documentation.DocumentationProvider; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.PsiManager; 7 | import org.intellij.lang.jflex.psi.JFlexMacroDefinition; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * Created by IntelliJ IDEA. 14 | * User: Max 15 | * Date: 01.04.2008 16 | * Time: 23:25:17 17 | */ 18 | public class JFlexDocumentationProvider implements DocumentationProvider { 19 | 20 | @Nullable 21 | public String getQuickNavigateInfo(PsiElement element) { 22 | return null; 23 | } 24 | 25 | @Nullable 26 | public List getUrlFor(PsiElement element, PsiElement originalElement) { 27 | return null; 28 | } 29 | 30 | @Nullable 31 | public String generateDoc(PsiElement element, PsiElement originalElement) { 32 | if (element instanceof JFlexMacroDefinition) { 33 | ASTNode astNode = element.getNode(); 34 | ASTNode regexp = astNode != null ? astNode.findChildByType(JFlexElementTypes.REGEXP) : null; 35 | return regexp != null ? regexp.getText() : "No regexp found."; 36 | } 37 | return null; 38 | } 39 | 40 | @Nullable 41 | public PsiElement getDocumentationElementForLookupItem(PsiManager psiManager, Object object, PsiElement element) { 42 | return null; 43 | } 44 | 45 | @Nullable 46 | public PsiElement getDocumentationElementForLink(PsiManager psiManager, String link, PsiElement context) { 47 | return null; 48 | } 49 | 50 | @Nullable 51 | public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) { 52 | return null; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/JFlexElementType.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex; 2 | 3 | import com.intellij.psi.tree.IElementType; 4 | import org.jetbrains.annotations.NonNls; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.text.MessageFormat; 8 | 9 | public class JFlexElementType extends IElementType { 10 | private final IElementType parsedType; 11 | 12 | public JFlexElementType(@NotNull @NonNls String debugName, IElementType parsedType) { 13 | super(debugName, JFlexLanguage.LANGUAGE); 14 | this.parsedType = parsedType; 15 | } 16 | 17 | public JFlexElementType(@NotNull @NonNls String debugName) { 18 | this(debugName, null); 19 | } 20 | 21 | public IElementType getParsedType() { 22 | return parsedType != null ? parsedType : this; 23 | } 24 | 25 | @SuppressWarnings({"HardCodedStringLiteral"}) 26 | public String toString() { 27 | return MessageFormat.format("JFlex:{0}", super.toString()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/JFlexElementTypes.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex; 2 | 3 | import com.intellij.lang.Language; 4 | import com.intellij.psi.TokenType; 5 | import com.intellij.psi.tree.IElementType; 6 | import com.intellij.psi.tree.IFileElementType; 7 | import com.intellij.psi.tree.TokenSet; 8 | 9 | public interface JFlexElementTypes { 10 | IFileElementType FILE = new IFileElementType(JFlexLanguage.LANGUAGE); 11 | 12 | IElementType BAD_CHARACTER = TokenType.BAD_CHARACTER; 13 | IElementType WHITE_SPACE = TokenType.WHITE_SPACE; 14 | 15 | IElementType STRING_LITERAL = new JFlexElementType("STRING_LITERAL"); 16 | IElementType IDENTIFIER = new JFlexElementType("IDENTIFIER"); 17 | 18 | IElementType JAVA_CODE = new JFlexElementType("JAVA_CODE"); 19 | IElementType COMMENT = new JFlexElementType("COMMENT"); 20 | 21 | IElementType MACROS = new JFlexElementType("MACROS"); 22 | IElementType MACROS_REF = new JFlexElementType("MACROS_REF"); 23 | 24 | IElementType EQ = new JFlexElementType("EQ"); 25 | IElementType COMMA = new JFlexElementType("COMMA"); 26 | IElementType OR = new JFlexElementType("OR"); 27 | 28 | IElementType LEFT_BRACE = new JFlexElementType("LEFT_BRACE"); 29 | IElementType RIGHT_BRACE = new JFlexElementType("RIGHT_BRACE"); 30 | IElementType RIGHT_BRACKET = new JFlexElementType("RIGHT_BRACKET"); 31 | IElementType LEFT_BRACKET = new JFlexElementType("LEFT_BRACKET"); 32 | IElementType RIGHT_ANGLE_BRACKET = new JFlexElementType("RIGHT_ANGLE_BRACKET"); 33 | IElementType LEFT_ANGLE_BRACKET = new JFlexElementType("LEFT_ANGLE_BRACKET"); 34 | IElementType RIGHT_PARENTHESIS = new JFlexElementType("RIGHT_PARENTHESIS"); 35 | IElementType LEFT_PARENTHESIS = new JFlexElementType("LEFT_PARENTHESIS"); 36 | 37 | IElementType SECTION_SIGN = new JFlexElementType("SECTION_SIGN"); 38 | 39 | IElementType OPTION_SIGN = new JFlexElementType("OPTION_SIGN"); 40 | IElementType OPTION_PARAMETER = new JFlexElementType("OPTION_PARAMETER", IDENTIFIER); 41 | IElementType OPTION_WHITE_SPACE = new JFlexElementType("OPTION_WHITE_SPACE", WHITE_SPACE); 42 | IElementType OPTION_LEFT_BRACE = new JFlexElementType("OPTION_LEFT_BRACE", LEFT_BRACE); 43 | IElementType OPTION_RIGHT_BRACE = new JFlexElementType("OPTION_RIGHT_BRACE", RIGHT_BRACE); 44 | IElementType OPTION_COMMA = new JFlexElementType("OPTION_COMMA", COMMA); 45 | 46 | IElementType STATE_REF = new JFlexElementType("STATE_REF", IDENTIFIER); 47 | IElementType STATE_COMMA = new JFlexElementType("STATE_COMMA", COMMA); 48 | IElementType STATE_LEFT_ANGLE_BRACKET = new JFlexElementType("STATE_LEFT_ANGLE_BRACKET", LEFT_ANGLE_BRACKET); 49 | IElementType STATE_RIGHT_ANGLE_BRACKET = new JFlexElementType("STATE_LEFT_ANGLE_BRACKET", RIGHT_ANGLE_BRACKET); 50 | 51 | IElementType REGEXP_WHITE_SPACE = new JFlexElementType("REGEXP_WHITE_SPACE", WHITE_SPACE); 52 | IElementType REGEXP_PREFIX = new JFlexElementType("REGEXP_PREFIX"); 53 | IElementType REGEXP_POSTFIX = new JFlexElementType("REGEXP_PREFIX"); 54 | IElementType REGEXP_SYMBOL = new JFlexElementType("REGEXP_SYMBOL"); 55 | IElementType REGEXP_CLASS_SYMBOL = new JFlexElementType("REGEXP_CLASS_SYMBOL", REGEXP_SYMBOL); 56 | IElementType REGEXP_LEFT_BRACKET = new JFlexElementType("REGEXP_LEFT_BRACKET", LEFT_BRACKET); 57 | IElementType REGEXP_RIGHT_BRACKET = new JFlexElementType("REGEXP_RIGHT_BRACKET", RIGHT_BRACKET); 58 | IElementType REGEXP_LEFT_BRACE = new JFlexElementType("REGEXP_LEFT_BRACE", LEFT_BRACE); 59 | IElementType REGEXP_RIGHT_BRACE = new JFlexElementType("REGEXP_RIGHT_BRACE", RIGHT_BRACE); 60 | IElementType REGEXP_LEFT_PARENTHESIS = new JFlexElementType("REGEXP_LEFT_PARENTHESIS", LEFT_PARENTHESIS); 61 | IElementType REGEXP_RIGHT_PARENTHESIS = new JFlexElementType("REGEXP_RIGHT_PARENTHESIS", RIGHT_PARENTHESIS); 62 | IElementType REGEXP_OR = new JFlexElementType("REGEXP_OR", OR); 63 | IElementType REGEXP_STRING_LITERAL = new JFlexElementType("REGEXP_STRING_LITERAL", STRING_LITERAL); 64 | IElementType REGEXP_MACROS_REF = new JFlexElementType("REGEXP_MACROS_REF", MACROS_REF); 65 | 66 | IElementType CLASS_KEYWORD = new JFlexElementType("CLASS_KEYWORD"); 67 | IElementType IMPLEMENTS_KEYWORD = new JFlexElementType("IMPLEMENTS_KEYWORD"); 68 | IElementType EXTENDS_KEYWORD = new JFlexElementType("EXTENDS_KEYWORD"); 69 | IElementType PUBLIC_KEYWORD = new JFlexElementType("PUBLIC_KEYWORD"); 70 | IElementType FINAL_KEYWORD = new JFlexElementType("FINAL_KEYWORD"); 71 | IElementType ABSTRACT_KEYWORD = new JFlexElementType("ABSTRACT_KEYWORD"); 72 | IElementType APIPRIVATE_KEYWORD = new JFlexElementType("APIPRIVATE_KEYWORD"); 73 | IElementType INIT_KEYWORD = new JFlexElementType("INIT_KEYWORD"); 74 | IElementType INITTHROW_KEYWORD = new JFlexElementType("INITTHROW_KEYWORD"); 75 | IElementType SCANERROR_KEYWORD = new JFlexElementType("SCANERROR_KEYWORD"); 76 | IElementType BUFFERSIZE_KEYWORD = new JFlexElementType("BUFFERSIZE_KEYWORD"); 77 | IElementType INCLUDE_KEYWORD = new JFlexElementType("INCLUDE_KEYWORD"); 78 | IElementType FUNCTION_KEYWORD = new JFlexElementType("FUNCTION_KEYWORD"); 79 | IElementType INT_KEYWORD = new JFlexElementType("INT_KEYWORD"); 80 | IElementType INTEGER_KEYWORD = new JFlexElementType("INTEGER_KEYWORD"); 81 | IElementType INTWRAP_KEYWORD = new JFlexElementType("INTWRAP_KEYWORD"); 82 | IElementType TYPE_KEYWORD = new JFlexElementType("TYPE_KEYWORD"); 83 | IElementType YYLEXTHROW_KEYWORD = new JFlexElementType("YYLEXTHROW_KEYWORD"); 84 | IElementType EOF_KEYWORD = new JFlexElementType("EOF_KEYWORD"); 85 | IElementType EOFVAL_KEYWORD = new JFlexElementType("EOFVAL_KEYWORD"); 86 | IElementType EOFTHROW_KEYWORD = new JFlexElementType("EOFTHROW_KEYWORD"); 87 | IElementType EOFCLOSE_KEYWORD = new JFlexElementType("EOFCLOSE_KEYWORD"); 88 | IElementType DEBUG_KEYWORD = new JFlexElementType("DEBUG_KEYWORD"); 89 | IElementType STANDALONE_KEYWORD = new JFlexElementType("STANDALONE_KEYWORD"); 90 | IElementType CUP_KEYWORD = new JFlexElementType("CUP_KEYWORD"); 91 | IElementType CUPSYM_KEYWORD = new JFlexElementType("CUPSYM_KEYWORD"); 92 | IElementType CUPDEBUG_KEYWORD = new JFlexElementType("CUPDEBUG_KEYWORD"); 93 | IElementType BYACC_KEYWORD = new JFlexElementType("BYACC_KEYWORD"); 94 | IElementType SWITCH_KEYWORD = new JFlexElementType("SWITCH_KEYWORD"); 95 | IElementType TABLE_KEYWORD = new JFlexElementType("TABLE_KEYWORD"); 96 | IElementType PACK_KEYWORD = new JFlexElementType("PACK_KEYWORD"); 97 | IElementType _7BIT_KEYWORD = new JFlexElementType("7BIT_KEYWORD"); 98 | IElementType _8BIT_KEYWORD = new JFlexElementType("8BIT_KEYWORD"); 99 | IElementType _16BIT_KEYWORD = new JFlexElementType("16BIT_KEYWORD"); 100 | IElementType FULL_KEYWORD = new JFlexElementType("FULL_KEYWORD"); 101 | IElementType UNICODE_KEYWORD = new JFlexElementType("UNICODE_KEYWORD"); 102 | IElementType CASELESS_KEYWORD = new JFlexElementType("CASELESS_KEYWORD"); 103 | IElementType IGNORECASE_KEYWORD = new JFlexElementType("IGNORECASE_KEYWORD"); 104 | IElementType CHAR_KEYWORD = new JFlexElementType("CHAR_KEYWORD"); 105 | IElementType LINE_KEYWORD = new JFlexElementType("LINE_KEYWORD"); 106 | IElementType COLUMN_KEYWORD = new JFlexElementType("COLUMN_KEYWORD"); 107 | IElementType NOTUNIX_KEYWORD = new JFlexElementType("NOTUNIX_KEYWORD"); 108 | IElementType YYEOF_KEYWORD = new JFlexElementType("YYEOF_KEYWORD"); 109 | IElementType STATE_KEYWORD = new JFlexElementType("STATE_KEYWORD"); 110 | IElementType S_KEYWORD = new JFlexElementType("S_KEYWORD"); 111 | IElementType XSTATE_KEYWORD = new JFlexElementType("XSTATE_KEYWORD"); 112 | IElementType X_KEYWORD = new JFlexElementType("X_KEYWORD"); 113 | IElementType FALSE_KEYWORD = new JFlexElementType("FALSE_KEYWORD"); 114 | IElementType TRUE_KEYWORD = new JFlexElementType("TRUE_KEYWORD"); 115 | 116 | TokenSet OPTION_KEYWORDS = TokenSet.create( 117 | CLASS_KEYWORD, 118 | IMPLEMENTS_KEYWORD, 119 | EXTENDS_KEYWORD, 120 | PUBLIC_KEYWORD, 121 | FINAL_KEYWORD, 122 | ABSTRACT_KEYWORD, 123 | APIPRIVATE_KEYWORD, 124 | INIT_KEYWORD, 125 | INITTHROW_KEYWORD, 126 | SCANERROR_KEYWORD, 127 | BUFFERSIZE_KEYWORD, 128 | INCLUDE_KEYWORD, 129 | FUNCTION_KEYWORD, 130 | INT_KEYWORD, 131 | INTEGER_KEYWORD, 132 | INTWRAP_KEYWORD, 133 | TYPE_KEYWORD, 134 | YYLEXTHROW_KEYWORD, 135 | EOF_KEYWORD, 136 | EOFVAL_KEYWORD, 137 | EOFTHROW_KEYWORD, 138 | EOFCLOSE_KEYWORD, 139 | DEBUG_KEYWORD, 140 | STANDALONE_KEYWORD, 141 | CUP_KEYWORD, 142 | CUPSYM_KEYWORD, 143 | CUPDEBUG_KEYWORD, 144 | BYACC_KEYWORD, 145 | SWITCH_KEYWORD, 146 | TABLE_KEYWORD, 147 | PACK_KEYWORD, 148 | _7BIT_KEYWORD, 149 | _8BIT_KEYWORD, 150 | _16BIT_KEYWORD, 151 | FULL_KEYWORD, 152 | UNICODE_KEYWORD, 153 | CASELESS_KEYWORD, 154 | IGNORECASE_KEYWORD, 155 | CHAR_KEYWORD, 156 | LINE_KEYWORD, 157 | COLUMN_KEYWORD, 158 | NOTUNIX_KEYWORD, 159 | YYEOF_KEYWORD, 160 | STATE_KEYWORD, 161 | S_KEYWORD, 162 | XSTATE_KEYWORD, 163 | X_KEYWORD, 164 | FALSE_KEYWORD, 165 | TRUE_KEYWORD 166 | ); 167 | 168 | TokenSet OPERATORS = TokenSet.create( 169 | EQ, 170 | OR 171 | ); 172 | 173 | TokenSet BRACES = TokenSet.create( 174 | LEFT_BRACE, 175 | RIGHT_BRACE 176 | ); 177 | 178 | TokenSet BRACKETS = TokenSet.create( 179 | LEFT_BRACKET, 180 | RIGHT_BRACKET 181 | ); 182 | 183 | TokenSet PARENTHESES = TokenSet.create( 184 | LEFT_PARENTHESIS, 185 | RIGHT_PARENTHESIS 186 | ); 187 | 188 | TokenSet ANGLE_BRACKETS = TokenSet.create( 189 | LEFT_ANGLE_BRACKET, 190 | RIGHT_ANGLE_BRACKET 191 | ); 192 | 193 | TokenSet OPTION_SCOPE = TokenSet.orSet(OPTION_KEYWORDS, TokenSet.create( 194 | OPTION_COMMA, 195 | OPTION_LEFT_BRACE, 196 | OPTION_RIGHT_BRACE, 197 | OPTION_SIGN, 198 | OPTION_WHITE_SPACE, 199 | OPTION_PARAMETER 200 | )); 201 | 202 | TokenSet REGEXP_SCOPE = TokenSet.create( 203 | REGEXP_STRING_LITERAL, 204 | REGEXP_CLASS_SYMBOL, 205 | REGEXP_LEFT_BRACKET, 206 | REGEXP_LEFT_PARENTHESIS, 207 | REGEXP_LEFT_BRACE, 208 | REGEXP_RIGHT_BRACKET, 209 | REGEXP_RIGHT_PARENTHESIS, 210 | REGEXP_RIGHT_BRACE, 211 | REGEXP_OR, 212 | REGEXP_POSTFIX, 213 | REGEXP_PREFIX, 214 | REGEXP_SYMBOL, 215 | REGEXP_MACROS_REF, 216 | REGEXP_WHITE_SPACE 217 | ); 218 | 219 | TokenSet STATE_SCOPE = TokenSet.create( 220 | STATE_COMMA, 221 | STATE_REF, 222 | STATE_LEFT_ANGLE_BRACKET, 223 | STATE_RIGHT_ANGLE_BRACKET 224 | ); 225 | 226 | TokenSet WHITE_SPACES = TokenSet.create( 227 | WHITE_SPACE, 228 | OPTION_WHITE_SPACE, 229 | REGEXP_WHITE_SPACE 230 | ); 231 | 232 | TokenSet COMMENTS = TokenSet.create(COMMENT); 233 | 234 | TokenSet EXPRESSIONS = TokenSet.create( 235 | OPTION_PARAMETER 236 | ); 237 | 238 | 239 | /** 240 | * Composite elements 241 | */ 242 | 243 | IElementType SECTION = new JFlexElementType("SECTION"); 244 | IElementType CLASS_STATEMENT = new JFlexElementType("CLASS_STATEMENT"); 245 | IElementType TYPE_STATEMENT = new JFlexElementType("TYPE_STATEMENT"); 246 | IElementType IMPLEMENTS_STATEMENT = new JFlexElementType("IMPLEMENTS_STATEMENT"); 247 | IElementType STATE_STATEMENT = new JFlexElementType("STATE_STATEMENT"); 248 | IElementType STATE_DEFINITION = new JFlexElementType("STATE_DEFINITION"); 249 | IElementType MACRO_DEFINITION = new JFlexElementType("MACRO_DEFINITION"); 250 | IElementType REGEXP = new JFlexElementType("REGEXP"); 251 | 252 | 253 | TokenSet IDENTIFIERS = TokenSet.create(STATE_DEFINITION, MACRO_DEFINITION, MACROS_REF, STATE_REF); 254 | 255 | } 256 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/JFlexFindUsagesProvider.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex; 2 | 3 | import com.intellij.lang.cacheBuilder.DefaultWordsScanner; 4 | import com.intellij.lang.cacheBuilder.WordsScanner; 5 | import com.intellij.lang.findUsages.FindUsagesProvider; 6 | import com.intellij.psi.PsiElement; 7 | import com.intellij.psi.PsiNamedElement; 8 | import org.intellij.lang.jflex.lexer.JFlexMergingLexer; 9 | import org.intellij.lang.jflex.psi.JFlexMacroDefinition; 10 | import org.intellij.lang.jflex.psi.JFlexStateDefinition; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.jetbrains.annotations.Nullable; 13 | 14 | /** 15 | * Created by IntelliJ IDEA. 16 | * User: Max 17 | * Date: 01.04.2008 18 | * Time: 23:31:29 19 | */ 20 | public class JFlexFindUsagesProvider implements FindUsagesProvider { 21 | 22 | public boolean canFindUsagesFor(@NotNull PsiElement psiElement) { 23 | return psiElement instanceof PsiNamedElement; 24 | } 25 | 26 | @NotNull 27 | public String getDescriptiveName(@NotNull PsiElement element) { 28 | String name = ((PsiNamedElement) element).getName(); 29 | return name != null ? name : ""; 30 | } 31 | 32 | @Nullable 33 | public String getHelpId(@NotNull PsiElement psiElement) { 34 | return null; 35 | } 36 | 37 | @NotNull 38 | public String getNodeText(@NotNull PsiElement element, boolean useFullName) { 39 | return getDescriptiveName(element); 40 | } 41 | 42 | @NotNull 43 | public String getType(@NotNull PsiElement element) { 44 | if (element instanceof JFlexStateDefinition) return "State"; 45 | if (element instanceof JFlexMacroDefinition) return "Macro"; 46 | return ""; 47 | } 48 | 49 | @Nullable 50 | public WordsScanner getWordsScanner() { 51 | return new DefaultWordsScanner(new JFlexMergingLexer(), JFlexElementTypes.IDENTIFIERS, JFlexElementTypes.COMMENTS, JFlexElementTypes.REGEXP_SCOPE); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/JFlexLanguage.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex; 2 | 3 | import com.intellij.lang.Language; 4 | import com.intellij.openapi.fileTypes.SingleLazyInstanceSyntaxHighlighterFactory; 5 | import com.intellij.openapi.fileTypes.SyntaxHighlighter; 6 | import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory; 7 | import org.intellij.lang.jflex.fileTypes.JFlexSyntaxHighlighter; 8 | import org.jetbrains.annotations.NonNls; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | /** 12 | * JFlex language. 13 | * 14 | * @author Alexey Efimov 15 | */ 16 | public class JFlexLanguage extends Language { 17 | @NonNls 18 | public static final String ID = "JFlex"; 19 | 20 | public static final JFlexLanguage LANGUAGE = new JFlexLanguage(); 21 | 22 | public JFlexLanguage() { 23 | super(ID); 24 | 25 | //somehow lang.syntaxHighlighterFactory extension won't work for me 26 | SyntaxHighlighterFactory.LANGUAGE_FACTORY.addExplicitExtension(this, new SingleLazyInstanceSyntaxHighlighterFactory() { 27 | @NotNull 28 | protected SyntaxHighlighter createHighlighter() { 29 | return new JFlexSyntaxHighlighter(); 30 | } 31 | }); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/compiler/JFlex.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.compiler; 2 | 3 | import com.intellij.execution.CantRunException; 4 | import com.intellij.execution.configurations.CommandLineBuilder; 5 | import com.intellij.execution.configurations.JavaParameters; 6 | import com.intellij.openapi.application.Application; 7 | import com.intellij.openapi.application.ApplicationManager; 8 | import com.intellij.openapi.compiler.CompilerMessageCategory; 9 | import com.intellij.openapi.options.ShowSettingsUtil; 10 | import com.intellij.openapi.project.Project; 11 | import com.intellij.openapi.projectRoots.Sdk; 12 | import com.intellij.openapi.ui.Messages; 13 | import com.intellij.openapi.util.SystemInfo; 14 | import com.intellij.openapi.util.io.StreamUtil; 15 | import com.intellij.openapi.util.text.StringUtil; 16 | import com.intellij.openapi.vfs.VirtualFile; 17 | import org.intellij.lang.jflex.options.JFlexConfigurable; 18 | import org.intellij.lang.jflex.options.JFlexSettings; 19 | import org.intellij.lang.jflex.util.JFlexBundle; 20 | import org.jetbrains.annotations.NonNls; 21 | import org.jetbrains.annotations.NotNull; 22 | 23 | import java.io.File; 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | import java.text.MessageFormat; 27 | import java.util.ArrayList; 28 | import java.util.HashMap; 29 | import java.util.List; 30 | import java.util.Map; 31 | import java.util.regex.Matcher; 32 | import java.util.regex.Pattern; 33 | 34 | /** 35 | * JFlexx wrapper to command line tool. 36 | * 37 | * @author Alexey Efimov 38 | */ 39 | public final class JFlex { 40 | @NonNls 41 | private static final Pattern LINE_NUMBER_PATTERN = Pattern.compile(".*?\\(line\\s(\\d+)\\)\\:\\s*?$"); 42 | 43 | @NonNls 44 | private static final String JFLEX_MAIN_CLASS = "JFlex.Main"; 45 | @NonNls 46 | private static final String JFLEX_JAR_PATH = "./lib/JFlex.jar"; 47 | @NonNls 48 | public static final String BIN_BASH = "/bin/bash"; 49 | @NonNls 50 | public static final String HYPHEN_C = "-c"; 51 | @NonNls 52 | public static final String SLASH_C = "/C"; 53 | @NonNls 54 | private static final String COMMAND_COM = "command.com"; 55 | @NonNls 56 | private static final String CMD_EXE = "cmd.exe"; 57 | @NonNls 58 | private static final String OPTION_SKEL = " --skel "; 59 | @NonNls 60 | private static final String OPTION_D = " -d "; 61 | @NonNls 62 | private static final String OPTION_QUIET = " --quiet "; 63 | @NonNls 64 | private static final String OPTION_Q = " -q "; 65 | @NonNls 66 | private static final char QUOT = '"'; 67 | @NonNls 68 | private static final char SPACE = ' '; 69 | 70 | @NotNull 71 | public static Map> compile(VirtualFile file, Sdk projectSdk) throws IOException, CantRunException { 72 | 73 | JFlexSettings settings = JFlexSettings.getInstance(); 74 | 75 | //Earlier code used jflex.bat or jflex.sh. These files are broken after IDEA went open-source and changed 76 | //its sdk distribution structure. It's better to call JFlex.Main directly, not using any dumb bat or sh files. 77 | JavaParameters javaParameters = new JavaParameters(); 78 | javaParameters.setJdk(projectSdk); 79 | javaParameters.setMainClass(JFLEX_MAIN_CLASS); 80 | javaParameters.getClassPath().add(JFLEX_JAR_PATH); 81 | 82 | StringBuilder command = new StringBuilder(CommandLineBuilder.createFromJavaParameters(javaParameters).getCommandLineString()); 83 | 84 | //That options stuff can be refactored using javaParameters.getProgramParametersList().add(anOption), 85 | //as it does auto-quoting if necessary. 86 | String options = MessageFormat.format(" {0} ", settings.COMMAND_LINE_OPTIONS); 87 | if (!StringUtil.isEmptyOrSpaces(options)) { 88 | command.append(options); 89 | } 90 | if (!StringUtil.isEmptyOrSpaces(settings.SKELETON_PATH) && options.indexOf(OPTION_SKEL) == -1) { 91 | command.append(OPTION_SKEL).append(QUOT).append(settings.SKELETON_PATH).append(QUOT); 92 | } 93 | if (options.indexOf(OPTION_Q) == -1 && options.indexOf(OPTION_QUIET) == -1) { 94 | command.append(OPTION_QUIET); 95 | } 96 | VirtualFile parent = file.getParent(); 97 | if (parent != null) { 98 | command.append(OPTION_D).append(QUOT).append(parent.getPath()).append(QUOT); 99 | } 100 | command.append(SPACE).append(QUOT).append(file.getPath()).append(QUOT); 101 | 102 | String shell = SystemInfo.isWindows ? SystemInfo.isWin2kOrNewer ? CMD_EXE : COMMAND_COM : BIN_BASH; 103 | String[] commands; 104 | if (SystemInfo.isWindows) { 105 | commands = new String[]{shell, SLASH_C, QUOT + command.toString() + QUOT}; 106 | } else { 107 | commands = new String[]{shell, HYPHEN_C, command.toString()}; 108 | } 109 | Process process = Runtime.getRuntime().exec(commands, null, new File(settings.JFLEX_HOME)); 110 | try { 111 | InputStream out = process.getInputStream(); 112 | try { 113 | InputStream err = process.getErrorStream(); 114 | try { 115 | List information = new ArrayList(); 116 | List error = new ArrayList(); 117 | filter(StreamUtil.readText(out), information, error); 118 | filter(StreamUtil.readText(err), information, error); 119 | Map> messages = new HashMap>(); 120 | messages.put(CompilerMessageCategory.ERROR, error); 121 | messages.put(CompilerMessageCategory.INFORMATION, information); 122 | int code = 0; 123 | try { 124 | code = process.waitFor(); 125 | } catch (InterruptedException e) { 126 | List warnings = new ArrayList(); 127 | warnings.add(new JFlexMessage("Interrupted while waiting for Jflex to complete")); 128 | messages.put(CompilerMessageCategory.WARNING, warnings); 129 | } 130 | if (code == 0) { 131 | return messages; 132 | } else { 133 | if (messages.get(CompilerMessageCategory.ERROR).size() > 0) { 134 | return messages; 135 | } 136 | throw new IOException(JFlexBundle.message("command.0.execution.failed.with.exit.code.1", command, code)); 137 | } 138 | } finally { 139 | err.close(); 140 | } 141 | } finally { 142 | out.close(); 143 | } 144 | } finally { 145 | process.destroy(); 146 | } 147 | } 148 | 149 | private static void filter(@NonNls String output, @NotNull List information, @NotNull List error) { 150 | if (!StringUtil.isEmptyOrSpaces(output)) { 151 | String[] lines = output.split("[\\n\\r]+"); 152 | for (int i = 0; i < lines.length; i++) { 153 | @NonNls String line = lines[i]; 154 | if (line.startsWith("Error in file") && i + 3 < lines.length) { 155 | // Parse "error in file" message 156 | // it look like: 157 | // Error in file "JFlex.flex" (line 72): 158 | // Syntax error. 159 | // { 160 | // ^ 161 | String message = lines[++i]; 162 | int lineNumber = -1; 163 | int columnNumber = -1; 164 | Matcher matcher = LINE_NUMBER_PATTERN.matcher(line); 165 | if (matcher.matches()) { 166 | try { 167 | lineNumber = Integer.parseInt(matcher.group(1)); 168 | } catch (NumberFormatException e) { 169 | // Ignore 170 | } 171 | } 172 | // Skip line 173 | i++; 174 | char[] columnPointer = lines[++i].toCharArray(); 175 | for (int j = 0; columnNumber == -1 && j < columnPointer.length; j++) { 176 | char c = columnPointer[j]; 177 | if (c != ' ') { 178 | if (c == '^') { 179 | columnNumber = j + 1; 180 | } else { 181 | // It is invalid code pointer line 182 | // Rollback i to previous lines 183 | i -= 2; 184 | break; 185 | } 186 | } 187 | } 188 | error.add(new JFlexMessage(message, lineNumber, columnNumber)); 189 | } else if (!line.startsWith("Reading skeleton file")) { 190 | information.add(new JFlexMessage(line)); 191 | } 192 | } 193 | } 194 | } 195 | 196 | public static boolean validateConfiguration(Project project) { 197 | JFlexSettings settings = JFlexSettings.getInstance(); 198 | File home = new File(settings.JFLEX_HOME); 199 | if (home.isDirectory() && home.exists()) { 200 | if (!StringUtil.isEmptyOrSpaces(settings.SKELETON_PATH) && settings.COMMAND_LINE_OPTIONS.indexOf(OPTION_SKEL) == -1) { 201 | File skel = new File(settings.SKELETON_PATH); 202 | if (!skel.isFile() || !skel.exists()) { 203 | return showWarningMessageAndConfigure(project, JFlexBundle.message("jflex.skeleton.file.was.not.found")); 204 | } 205 | } 206 | 207 | File jarFile = new File(settings.JFLEX_HOME + "/" + JFLEX_JAR_PATH); 208 | if(!jarFile.isFile() || !jarFile.exists()) { 209 | return showWarningMessageAndConfigure(project, JFlexBundle.message("jar.not.found", JFLEX_JAR_PATH)); 210 | } 211 | } else { 212 | return showWarningMessageAndConfigure(project, JFlexBundle.message("jflex.home.path.is.invalid")); 213 | } 214 | return true; 215 | } 216 | 217 | private static boolean showWarningMessageAndConfigure(final Project project, String message) { 218 | Messages.showWarningDialog(project, message, JFlexBundle.message("jflex")); 219 | // Show settings 220 | final Application application = ApplicationManager.getApplication(); 221 | application.invokeLater(new Runnable() { 222 | public void run() { 223 | ShowSettingsUtil.getInstance().editConfigurable(project, application.getComponent(JFlexConfigurable.class)); 224 | } 225 | }); 226 | return false; 227 | } 228 | 229 | public static boolean isCompilationEnabled() { 230 | return JFlexSettings.getInstance().ENABLED_COMPILATION; 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/compiler/JFlexCompilerFactory.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.compiler; 2 | 3 | import com.intellij.openapi.compiler.*; 4 | import com.intellij.openapi.compiler.Compiler; 5 | import org.intellij.lang.jflex.fileTypes.JFlexFileType; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | /** 9 | * Creates a compiler for JFlex and attaches it to IDEA 10 | * 11 | * @author Jan Dolecek 12 | */ 13 | public class JFlexCompilerFactory implements CompilerFactory { 14 | @Override 15 | public Compiler[] createCompilers(@NotNull CompilerManager mgr) { 16 | mgr.addCompilableFileType(JFlexFileType.FILE_TYPE); 17 | mgr.addCompiler(new JFlexSourceGeneratingCompiler()); 18 | return new Compiler[0]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/compiler/JFlexMessage.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.compiler; 2 | 3 | import java.text.MessageFormat; 4 | 5 | /** 6 | * JFlex message. 7 | * 8 | * @author Alexey Efimov 9 | */ 10 | public final class JFlexMessage { 11 | private final int line; 12 | private final int column; 13 | private final String message; 14 | 15 | public JFlexMessage(String message, int line, int column) { 16 | this.line = line; 17 | this.column = column; 18 | this.message = message; 19 | } 20 | 21 | public JFlexMessage(String message) { 22 | this(message, -1, -1); 23 | } 24 | 25 | public int getLine() { 26 | return line; 27 | } 28 | 29 | public int getColumn() { 30 | return column; 31 | } 32 | 33 | public String getMessage() { 34 | return message; 35 | } 36 | 37 | public String toString() { 38 | return line >= 0 ? column >= 0 ? MessageFormat.format("{0} ({1}:{2})", message, line, column) : MessageFormat.format("{0} ({1})", message, line) : message; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/compiler/JFlexSourceGeneratingCompiler.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.compiler; 2 | 3 | import com.intellij.compiler.CompilerConfiguration; 4 | import com.intellij.compiler.impl.CompilerUtil; 5 | import com.intellij.execution.CantRunException; 6 | import com.intellij.lang.ASTNode; 7 | import com.intellij.openapi.application.Application; 8 | import com.intellij.openapi.application.ApplicationManager; 9 | import com.intellij.openapi.compiler.*; 10 | import com.intellij.openapi.components.ProjectComponent; 11 | import com.intellij.openapi.module.Module; 12 | import com.intellij.openapi.project.Project; 13 | import com.intellij.openapi.projectRoots.Sdk; 14 | import com.intellij.openapi.roots.ProjectFileIndex; 15 | import com.intellij.openapi.roots.ProjectRootManager; 16 | import com.intellij.openapi.util.Computable; 17 | import com.intellij.openapi.util.io.FileUtil; 18 | import com.intellij.openapi.vfs.VfsUtil; 19 | import com.intellij.openapi.vfs.VirtualFile; 20 | import com.intellij.psi.PsiFile; 21 | import com.intellij.psi.PsiManager; 22 | import org.intellij.lang.jflex.fileTypes.JFlexFileType; 23 | import org.intellij.lang.jflex.psi.JFlexElement; 24 | import org.intellij.lang.jflex.psi.JFlexPsiFile; 25 | import org.intellij.lang.jflex.util.JFlexBundle; 26 | import org.jetbrains.annotations.NonNls; 27 | import org.jetbrains.annotations.NotNull; 28 | 29 | import java.io.DataInput; 30 | import java.io.File; 31 | import java.io.IOException; 32 | import java.text.MessageFormat; 33 | import java.util.ArrayList; 34 | import java.util.List; 35 | import java.util.Map; 36 | 37 | /** 38 | * The source generating compiler for *.flex files. 39 | * 40 | * @author Alexey Efimov 41 | */ 42 | public class JFlexSourceGeneratingCompiler implements SourceGeneratingCompiler { 43 | @NonNls 44 | private static final String JAVA_FILE_NAME_PATTERN = "{0}.java"; 45 | private static final GenerationItem[] EMPTY_GENERATION_ITEM_ARRAY = new GenerationItem[]{}; 46 | 47 | public GenerationItem[] getGenerationItems(CompileContext context) { 48 | if (JFlex.isCompilationEnabled()) { 49 | Module[] affectedModules = context.getCompileScope().getAffectedModules(); 50 | if (affectedModules.length > 0) { 51 | Application application = ApplicationManager.getApplication(); 52 | return application.runReadAction(new PrepareAction(context)); 53 | } 54 | } 55 | return EMPTY_GENERATION_ITEM_ARRAY; 56 | } 57 | 58 | public GenerationItem[] generate(CompileContext context, GenerationItem[] items, VirtualFile outputRootDirectory) { 59 | if (JFlex.isCompilationEnabled()) { 60 | if (items != null && items.length > 0) { 61 | Application application = ApplicationManager.getApplication(); 62 | GenerationItem[] generationItems = application.runReadAction(new GenerateAction(context, items, outputRootDirectory, ProjectRootManager.getInstance(context.getProject()).getProjectSdk())); 63 | for (GenerationItem item : generationItems) { 64 | CompilerUtil.refreshIOFile(((JFlexGenerationItem) item).getGeneratedFile()); 65 | } 66 | return generationItems; 67 | } 68 | } 69 | return EMPTY_GENERATION_ITEM_ARRAY; 70 | } 71 | 72 | @NotNull 73 | public String getDescription() { 74 | return "jflex"; 75 | } 76 | 77 | public boolean validateConfiguration(CompileScope scope) { 78 | if (JFlex.isCompilationEnabled()) { 79 | Module[] affectedModules = scope.getAffectedModules(); 80 | if (affectedModules.length > 0) { 81 | Project project = affectedModules[0].getProject(); 82 | VirtualFile[] files = scope.getFiles(JFlexFileType.FILE_TYPE, false); 83 | if (files.length > 0) { 84 | return JFlex.validateConfiguration(project); 85 | } 86 | } 87 | } 88 | return true; 89 | } 90 | 91 | public ValidityState createValidityState(DataInput in) throws IOException { 92 | return TimestampValidityState.load(in); 93 | } 94 | 95 | @Override 96 | public VirtualFile getPresentableFile(CompileContext context, Module module, VirtualFile outputRoot, VirtualFile generatedFile) { 97 | return null; 98 | } 99 | 100 | private static class JFlexGenerationItem implements GenerationItem { 101 | private final Module module; 102 | private final boolean testSource; 103 | private final VirtualFile file; 104 | private final String generatedClassName; 105 | private final File generatedFile; 106 | private String path; 107 | 108 | public JFlexGenerationItem(Module module, VirtualFile file, boolean testSource) { 109 | this.file = file; 110 | this.module = module; 111 | this.testSource = testSource; 112 | String generationName = null; 113 | PsiFile psiFile = PsiManager.getInstance(module.getProject()).findFile(file); 114 | if (psiFile instanceof JFlexPsiFile) { 115 | JFlexPsiFile flexPsiFile = (JFlexPsiFile) psiFile; 116 | ASTNode node = flexPsiFile.getNode(); 117 | if (node != null) { 118 | /* lazy-lazy parser won't actually parse a file it has not been opened in editor before. 119 | * let's persuade it pretending that we really need all the stuff in a file.*/ 120 | node.getPsi().getChildren(); 121 | JFlexElement generateName = flexPsiFile.getClassname(); 122 | if (generateName != null) { 123 | generationName = generateName.getText(); 124 | } 125 | } 126 | } 127 | this.generatedClassName = generationName; 128 | VirtualFile parent = file.getParent(); 129 | this.generatedFile = parent != null ? 130 | new File(VfsUtil.virtualToIoFile(parent), MessageFormat.format(JAVA_FILE_NAME_PATTERN, generatedClassName)) : 131 | null; 132 | } 133 | 134 | public VirtualFile getFile() { 135 | return file; 136 | } 137 | 138 | public void setPath(String path) { 139 | this.path = path; 140 | } 141 | 142 | public String getPath() { 143 | return path; 144 | } 145 | 146 | public ValidityState getValidityState() { 147 | return null; 148 | } 149 | 150 | public Module getModule() { 151 | return module; 152 | } 153 | 154 | @NotNull 155 | public File getGeneratedFile() { 156 | return generatedFile; 157 | } 158 | 159 | public boolean isTestSource() { 160 | return testSource; 161 | } 162 | } 163 | 164 | private final class PrepareAction implements Computable { 165 | private final CompileContext context; 166 | 167 | public PrepareAction(CompileContext context) { 168 | this.context = context; 169 | } 170 | 171 | public GenerationItem[] compute() { 172 | ProjectFileIndex fileIndex = ProjectRootManager.getInstance(context.getProject()).getFileIndex(); 173 | CompileScope compileScope = context.getCompileScope(); 174 | VirtualFile[] files = compileScope.getFiles(JFlexFileType.FILE_TYPE, false); 175 | List items = new ArrayList(files.length); 176 | CompilerConfiguration compilerConfiguration = CompilerConfiguration.getInstance(context.getProject()); 177 | for (VirtualFile file : files) { 178 | if (context.isMake() && compilerConfiguration.isExcludedFromCompilation(file)) { 179 | continue; 180 | } 181 | JFlexGenerationItem generationItem = new JFlexGenerationItem(context.getModuleByFile(file), file, fileIndex.isInTestSourceContent(file)); 182 | if (context.isMake()) { 183 | File generatedFile = generationItem.getGeneratedFile(); 184 | if (!generatedFile.exists() || generatedFile.lastModified() <= file.getTimeStamp()) { 185 | items.add(generationItem); 186 | } 187 | } else { 188 | items.add(generationItem); 189 | } 190 | } 191 | return items.toArray(new GenerationItem[items.size()]); 192 | } 193 | } 194 | 195 | private static class GenerateAction implements Computable { 196 | private final CompileContext context; 197 | private final GenerationItem[] items; 198 | private final Sdk projectSdk; 199 | private final File outputDir; 200 | 201 | public GenerateAction(CompileContext context, GenerationItem[] items, VirtualFile outputRootDirectory, Sdk projectSdk) { 202 | this.context = context; 203 | this.items = items; 204 | this.projectSdk = projectSdk; 205 | outputDir = VfsUtil.virtualToIoFile(outputRootDirectory); 206 | } 207 | 208 | public GenerationItem[] compute() { 209 | List results = new ArrayList(items.length); 210 | for (GenerationItem item : items) { 211 | if (item instanceof JFlexGenerationItem) { 212 | JFlexGenerationItem flexItem = (JFlexGenerationItem) item; 213 | VirtualFile file = flexItem.getFile(); 214 | if (file != null && file.isValid()) { 215 | try { 216 | Map> messages = JFlex.compile(file, projectSdk); 217 | addMessages(file, messages); 218 | if (messages.get(CompilerMessageCategory.ERROR).isEmpty()) { 219 | File outFile = flexItem.getGeneratedFile(); 220 | if (outFile.isFile() && outFile.exists()) { 221 | flexItem.setPath(FileUtil.getRelativePath(outputDir, outFile)); 222 | results.add(flexItem); 223 | } else { 224 | context.addMessage(CompilerMessageCategory.ERROR, JFlexBundle.message("file.not.generated"), file.getUrl(), -1, -1); 225 | } 226 | } 227 | } catch (IOException e) { 228 | context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), file.getUrl(), -1, -1); 229 | } catch (CantRunException e) { 230 | context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), file.getUrl(), -1, -1); 231 | } 232 | } 233 | } 234 | } 235 | return results.toArray(new GenerationItem[results.size()]); 236 | } 237 | 238 | private void addMessages(VirtualFile file, Map> messages) { 239 | for (CompilerMessageCategory category : messages.keySet()) { 240 | List messageList = messages.get(category); 241 | for (JFlexMessage message : messageList) { 242 | context.addMessage(category, message.getMessage(), file.getUrl(), message.getLine(), message.getColumn()); 243 | } 244 | } 245 | } 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/editor/JFlexHighlighterColors.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.editor; 2 | 3 | import com.intellij.openapi.editor.HighlighterColors; 4 | import com.intellij.openapi.editor.SyntaxHighlighterColors; 5 | import com.intellij.openapi.editor.colors.TextAttributesKey; 6 | import com.intellij.openapi.editor.markup.TextAttributes; 7 | 8 | import java.awt.*; 9 | 10 | /** 11 | * JFlex highlighter colors. 12 | * 13 | * @author Alexey Efimov 14 | */ 15 | public interface JFlexHighlighterColors { 16 | TextAttributesKey COMMENT = TextAttributesKey.createTextAttributesKey( 17 | "JFLEX.COMMENT", SyntaxHighlighterColors.JAVA_BLOCK_COMMENT.getDefaultAttributes() 18 | ); 19 | TextAttributesKey STRING = TextAttributesKey.createTextAttributesKey( 20 | "JFLEX.STRING", SyntaxHighlighterColors.STRING.getDefaultAttributes() 21 | ); 22 | TextAttributesKey COMMA = TextAttributesKey.createTextAttributesKey( 23 | "JFLEX_COMMA", SyntaxHighlighterColors.COMMA.getDefaultAttributes() 24 | ); 25 | TextAttributesKey OPERATION_SIGN = TextAttributesKey.createTextAttributesKey( 26 | "JFLEX_OPERATION_SIGN", SyntaxHighlighterColors.OPERATION_SIGN.getDefaultAttributes() 27 | ); 28 | TextAttributesKey BRACES = TextAttributesKey.createTextAttributesKey( 29 | "JFLEX_BRACES", SyntaxHighlighterColors.BRACES.getDefaultAttributes() 30 | ); 31 | TextAttributesKey BRACKETS = TextAttributesKey.createTextAttributesKey( 32 | "JFLEX_BRACES", SyntaxHighlighterColors.BRACKETS.getDefaultAttributes() 33 | ); 34 | TextAttributesKey ANGLE_BRACKETS = TextAttributesKey.createTextAttributesKey( 35 | "JFLEX_ANGLE_BRACKETS", SyntaxHighlighterColors.BRACKETS.getDefaultAttributes() 36 | ); 37 | TextAttributesKey PARENTHS = TextAttributesKey.createTextAttributesKey( 38 | "JFLEX_PARENTHS", SyntaxHighlighterColors.PARENTHS.getDefaultAttributes() 39 | ); 40 | TextAttributesKey SECTION_SIGN = TextAttributesKey.createTextAttributesKey( 41 | "JFLEX.SECTION_SIGN", new TextAttributes( 42 | new Color(0, 0x80, 0), new Color(0xed, 0xff, 0xed), null, null, Font.BOLD 43 | ) 44 | ); 45 | TextAttributesKey OPTION_KEYWORD = TextAttributesKey.createTextAttributesKey( 46 | "JFLEX.OPTION_KEYWORD", new TextAttributes(new Color(0, 0, 0xff), null, null, null, Font.BOLD) 47 | ); 48 | TextAttributesKey OPTION_SIGN = TextAttributesKey.createTextAttributesKey( 49 | "JFLEX.OPTION_SIGN", new TextAttributes(new Color(0, 0, 0x80), null, null, null, 0) 50 | ); 51 | TextAttributesKey OPTION_PARAMETER = TextAttributesKey.createTextAttributesKey( 52 | "JFLEX.OPTION_PARAMETER", new TextAttributes(new Color(0, 0, 0x80), null, null, null, 0) 53 | ); 54 | TextAttributesKey OPTION_BACKGROUND = TextAttributesKey.createTextAttributesKey( 55 | "JFLEX_OPTION_BACKGROUND", new TextAttributes(null, new Color(0xed, 0xff, 0xed), null, null, 0) 56 | ); 57 | TextAttributesKey JAVA_CODE = TextAttributesKey.createTextAttributesKey( 58 | "JFLEX.JAVA_CODE", new TextAttributes(null, new Color(0xff, 0xfc, 0xe4), null, null, 0) 59 | ); 60 | TextAttributesKey REGEXP_BACKGROUND = TextAttributesKey.createTextAttributesKey( 61 | "JFLEX_REGEXP_BACKGROUND", new TextAttributes(null, new Color(0xef, 0xef, 0xef), null, null, 0) 62 | ); 63 | TextAttributesKey REGEXP_SYMBOL = TextAttributesKey.createTextAttributesKey( 64 | "JFLEX_REGEXP_SYMBOL", new TextAttributes(Color.BLUE, null, null, null, 0) 65 | ); 66 | TextAttributesKey REGEXP_CLASS_SYMBOL = TextAttributesKey.createTextAttributesKey( 67 | "JFLEX_REGEXP_CLASS_SYMBOL", new TextAttributes(Color.BLUE, null, null, null, Font.BOLD) 68 | ); 69 | TextAttributesKey MACROS = TextAttributesKey.createTextAttributesKey( 70 | "JFLEX_MACROS", new TextAttributes(new Color(0, 0, 0x80), null, null, null, Font.BOLD) 71 | ); 72 | TextAttributesKey MACROS_REF = TextAttributesKey.createTextAttributesKey( 73 | "JFLEX_MACROS_REF", new TextAttributes(new Color(0, 0, 0x80), null, null, null, 0) 74 | ); 75 | TextAttributesKey STATE_REF = TextAttributesKey.createTextAttributesKey( 76 | "JFLEX_STATE_REF", new TextAttributes(new Color(0x66, 0x0e, 0x7a), null, null, null, Font.BOLD) 77 | ); 78 | 79 | TextAttributesKey BAD_CHARACTER = HighlighterColors.BAD_CHARACTER; 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/editor/colors/JFlexColorPage.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.editor.colors; 2 | 3 | import com.intellij.openapi.editor.colors.TextAttributesKey; 4 | import com.intellij.openapi.fileTypes.SyntaxHighlighter; 5 | import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory; 6 | import com.intellij.openapi.options.colors.AttributesDescriptor; 7 | import com.intellij.openapi.options.colors.ColorDescriptor; 8 | import com.intellij.openapi.options.colors.ColorSettingsPage; 9 | import com.intellij.lang.LanguageParserDefinitions; 10 | import com.intellij.lang.Language; 11 | import org.intellij.lang.jflex.JFlexLanguage; 12 | import org.intellij.lang.jflex.editor.JFlexHighlighterColors; 13 | import org.intellij.lang.jflex.fileTypes.JFlexFileType; 14 | import org.jetbrains.annotations.NonNls; 15 | import org.jetbrains.annotations.NotNull; 16 | import org.jetbrains.annotations.Nullable; 17 | 18 | import javax.swing.*; 19 | import java.util.HashSet; 20 | import java.util.Map; 21 | import java.util.Set; 22 | 23 | final class JFlexColorPage implements ColorSettingsPage { 24 | private static final AttributesDescriptor[] EMPTY_ATTRIBUTES_DESCRIPTOR_ARRAY = new AttributesDescriptor[]{}; 25 | private static final ColorDescriptor[] EMPTY_COLOR_DESCRIPTOR_ARRAY = new ColorDescriptor[]{}; 26 | 27 | private final Set attributeDescriptors = new HashSet(); 28 | 29 | public JFlexColorPage() { 30 | attributeDescriptors.add(new AttributesDescriptor("Angle brackets", JFlexHighlighterColors.ANGLE_BRACKETS)); 31 | attributeDescriptors.add(new AttributesDescriptor("Brackets", JFlexHighlighterColors.BRACKETS)); 32 | attributeDescriptors.add(new AttributesDescriptor("Comma", JFlexHighlighterColors.COMMA)); 33 | attributeDescriptors.add(new AttributesDescriptor("Braces", JFlexHighlighterColors.BRACES)); 34 | attributeDescriptors.add(new AttributesDescriptor("Parenths", JFlexHighlighterColors.PARENTHS)); 35 | attributeDescriptors.add(new AttributesDescriptor("Comment", JFlexHighlighterColors.COMMENT)); 36 | attributeDescriptors.add(new AttributesDescriptor("Java code", JFlexHighlighterColors.JAVA_CODE)); 37 | attributeDescriptors.add(new AttributesDescriptor("Macros", JFlexHighlighterColors.MACROS)); 38 | attributeDescriptors.add(new AttributesDescriptor("Macros reference", JFlexHighlighterColors.MACROS_REF)); 39 | attributeDescriptors.add(new AttributesDescriptor("Operator", JFlexHighlighterColors.OPERATION_SIGN)); 40 | attributeDescriptors.add(new AttributesDescriptor("Option", JFlexHighlighterColors.OPTION_BACKGROUND)); 41 | attributeDescriptors.add(new AttributesDescriptor("Option keyword", JFlexHighlighterColors.OPTION_KEYWORD)); 42 | attributeDescriptors.add(new AttributesDescriptor("Option parameter", JFlexHighlighterColors.OPTION_PARAMETER)); 43 | attributeDescriptors.add(new AttributesDescriptor("Option sign", JFlexHighlighterColors.OPTION_SIGN)); 44 | attributeDescriptors.add(new AttributesDescriptor("RegExp", JFlexHighlighterColors.REGEXP_BACKGROUND)); 45 | attributeDescriptors.add(new AttributesDescriptor("RegExp class symbol", JFlexHighlighterColors.REGEXP_CLASS_SYMBOL)); 46 | attributeDescriptors.add(new AttributesDescriptor("RegExp symbol", JFlexHighlighterColors.REGEXP_SYMBOL)); 47 | attributeDescriptors.add(new AttributesDescriptor("Section sign", JFlexHighlighterColors.SECTION_SIGN)); 48 | attributeDescriptors.add(new AttributesDescriptor("State reference", JFlexHighlighterColors.STATE_REF)); 49 | attributeDescriptors.add(new AttributesDescriptor("String", JFlexHighlighterColors.STRING)); 50 | } 51 | 52 | @Nullable 53 | public Map getAdditionalHighlightingTagToDescriptorMap() { 54 | return null; 55 | } 56 | 57 | @NotNull 58 | public AttributesDescriptor[] getAttributeDescriptors() { 59 | return attributeDescriptors.toArray(EMPTY_ATTRIBUTES_DESCRIPTOR_ARRAY); 60 | } 61 | 62 | @NotNull 63 | public ColorDescriptor[] getColorDescriptors() { 64 | return EMPTY_COLOR_DESCRIPTOR_ARRAY; 65 | } 66 | 67 | @NonNls 68 | @NotNull 69 | public String getDemoText() { 70 | return "package org.intellij.lang.jflex;\n" + 71 | "%%\n" + 72 | "%class Lexer\n" + 73 | "/* Macros */\n" + 74 | "LineTerminator = \\r|\\n|\\r\\n\n" + 75 | "WhiteSpace = ({LineTerminator} | [ \\t\\f])+\n" + 76 | "// States\n" + 77 | "%state SAMPLE\n" + 78 | "%%\n" + 79 | " {\n" + 80 | " // Rule\n" + 81 | " \"foo\" { foo(); }\n" + 82 | "}"; 83 | } 84 | 85 | @NotNull 86 | public String getDisplayName() { 87 | return "JFlex"; 88 | } 89 | 90 | @NotNull 91 | public SyntaxHighlighter getHighlighter() { 92 | Language jflexLanguage = JFlexLanguage.LANGUAGE; 93 | return SyntaxHighlighterFactory.getSyntaxHighlighter(jflexLanguage, null, null); 94 | } 95 | 96 | @Nullable 97 | public Icon getIcon() { 98 | return JFlexFileType.FILE_TYPE.getIcon(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/fileTypes/JFlexFileType.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.fileTypes; 2 | 3 | import com.intellij.openapi.fileTypes.LanguageFileType; 4 | import com.intellij.openapi.util.IconLoader; 5 | import org.intellij.lang.jflex.JFlexLanguage; 6 | import org.intellij.lang.jflex.util.JFlexBundle; 7 | import org.jetbrains.annotations.NonNls; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import javax.swing.*; 12 | 13 | /** 14 | * JFlex file type. 15 | * 16 | * @author Alexey Efimov 17 | */ 18 | public final class JFlexFileType extends LanguageFileType { 19 | public static final JFlexFileType FILE_TYPE = new JFlexFileType(); 20 | 21 | @NonNls 22 | public static final String DEFAULT_EXTENSION = "flex"; 23 | 24 | public JFlexFileType() { 25 | super(JFlexLanguage.LANGUAGE); 26 | } 27 | 28 | @NotNull 29 | @NonNls 30 | public String getDefaultExtension() { 31 | return DEFAULT_EXTENSION; 32 | } 33 | 34 | @NotNull 35 | public String getDescription() { 36 | return JFlexBundle.message("jflex.filetype.description"); 37 | } 38 | 39 | @Nullable 40 | public Icon getIcon() { 41 | return IconLoader.getIcon("/fileTypes/jflex.png"); 42 | } 43 | 44 | @NotNull 45 | @NonNls 46 | public String getName() { 47 | return "JFlex"; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/fileTypes/JFlexFileTypeFactory.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.fileTypes; 2 | 3 | import com.intellij.openapi.fileTypes.FileTypeConsumer; 4 | import com.intellij.openapi.fileTypes.FileTypeFactory; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * JFlex file type factory, tells IDEA about new file type 9 | * 10 | * @author Jan Dolecek 11 | */ 12 | public final class JFlexFileTypeFactory extends FileTypeFactory { 13 | @Override 14 | public void createFileTypes(@NotNull FileTypeConsumer consumer) { 15 | consumer.consume(JFlexFileType.FILE_TYPE, "flex;jflex"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/fileTypes/JFlexSyntaxHighlighter.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.fileTypes; 2 | 3 | import com.intellij.lexer.Lexer; 4 | import com.intellij.openapi.editor.colors.TextAttributesKey; 5 | import com.intellij.openapi.fileTypes.SyntaxHighlighterBase; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.openapi.vfs.VirtualFile; 8 | import com.intellij.psi.tree.IElementType; 9 | import org.intellij.lang.jflex.JFlexElementType; 10 | import org.intellij.lang.jflex.JFlexElementTypes; 11 | import org.intellij.lang.jflex.editor.JFlexHighlighterColors; 12 | import org.intellij.lang.jflex.lexer.JFlexHighlighterLexer; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | /** 19 | * JFlex syntax highlighter 20 | * 21 | * @author Alexey Efimov 22 | */ 23 | public final class JFlexSyntaxHighlighter extends SyntaxHighlighterBase { 24 | 25 | private final JFlexHighlighterLexer lexer; 26 | private final Map colors = new HashMap(); 27 | private final Map backgrounds = new HashMap(); 28 | 29 | public JFlexSyntaxHighlighter() { 30 | 31 | lexer = new JFlexHighlighterLexer(); 32 | 33 | fillMap(colors, JFlexElementTypes.BRACES, JFlexHighlighterColors.BRACES); 34 | fillMap(colors, JFlexElementTypes.BRACKETS, JFlexHighlighterColors.BRACKETS); 35 | fillMap(colors, JFlexElementTypes.PARENTHESES, JFlexHighlighterColors.PARENTHS); 36 | fillMap(colors, JFlexElementTypes.ANGLE_BRACKETS, JFlexHighlighterColors.ANGLE_BRACKETS); 37 | 38 | fillMap(colors, JFlexElementTypes.OPERATORS, JFlexHighlighterColors.OPERATION_SIGN); 39 | 40 | colors.put(JFlexElementTypes.BAD_CHARACTER, JFlexHighlighterColors.BAD_CHARACTER); 41 | colors.put(JFlexElementTypes.COMMENT, JFlexHighlighterColors.COMMENT); 42 | colors.put(JFlexElementTypes.STRING_LITERAL, JFlexHighlighterColors.STRING); 43 | colors.put(JFlexElementTypes.COMMA, JFlexHighlighterColors.COMMA); 44 | 45 | backgrounds.put(JFlexElementTypes.JAVA_CODE, JFlexHighlighterColors.JAVA_CODE); 46 | 47 | colors.put(JFlexElementTypes.MACROS, JFlexHighlighterColors.MACROS); 48 | colors.put(JFlexElementTypes.MACROS_REF, JFlexHighlighterColors.MACROS_REF); 49 | 50 | 51 | colors.put(JFlexElementTypes.STATE_REF, JFlexHighlighterColors.STATE_REF); 52 | 53 | fillMap(backgrounds, JFlexElementTypes.REGEXP_SCOPE, JFlexHighlighterColors.REGEXP_BACKGROUND); 54 | colors.put(JFlexElementTypes.REGEXP_SYMBOL, JFlexHighlighterColors.REGEXP_SYMBOL); 55 | colors.put(JFlexElementTypes.REGEXP_CLASS_SYMBOL, JFlexHighlighterColors.REGEXP_CLASS_SYMBOL); 56 | 57 | fillMap(backgrounds, JFlexElementTypes.OPTION_SCOPE, JFlexHighlighterColors.OPTION_BACKGROUND); 58 | fillMap(colors, JFlexElementTypes.OPTION_KEYWORDS, JFlexHighlighterColors.OPTION_KEYWORD); 59 | colors.put(JFlexElementTypes.OPTION_PARAMETER, JFlexHighlighterColors.OPTION_PARAMETER); 60 | colors.put(JFlexElementTypes.OPTION_SIGN, JFlexHighlighterColors.OPTION_SIGN); 61 | 62 | colors.put(JFlexElementTypes.SECTION_SIGN, JFlexHighlighterColors.SECTION_SIGN); 63 | } 64 | 65 | @NotNull 66 | public Lexer getHighlightingLexer() { 67 | return lexer; 68 | } 69 | 70 | @NotNull 71 | public TextAttributesKey[] getTokenHighlights(IElementType tokenType) { 72 | return pack(getAttributeKeys(tokenType, backgrounds), getAttributeKeys(tokenType, colors)); 73 | } 74 | 75 | private TextAttributesKey getAttributeKeys(IElementType tokenType, Map map) { 76 | TextAttributesKey attributes = map.get(tokenType); 77 | if (attributes == null && tokenType instanceof JFlexElementType) { 78 | return map.get(((JFlexElementType) tokenType).getParsedType()); 79 | } 80 | return map.get(tokenType); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/injection/EmbeddedJavaLiteralTextEscaper.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.injection; 2 | 3 | import com.intellij.openapi.util.TextRange; 4 | import com.intellij.psi.LiteralTextEscaper; 5 | import org.intellij.lang.jflex.psi.JFlexJavaCode; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | /** 9 | * Created by IntelliJ IDEA. 10 | * User: Max 11 | * Date: 15.03.2008 12 | * Time: 21:01:02 13 | */ 14 | public class EmbeddedJavaLiteralTextEscaper extends LiteralTextEscaper { 15 | 16 | public EmbeddedJavaLiteralTextEscaper(@NotNull JFlexJavaCode host) { 17 | super(host); 18 | } 19 | 20 | public boolean decode(@NotNull TextRange textrange, @NotNull StringBuilder stringbuilder) { 21 | stringbuilder.append(myHost.getText(), textrange.getStartOffset(), textrange.getEndOffset()); 22 | return true; 23 | } 24 | 25 | public int getOffsetInHost(int i, @NotNull TextRange textrange) { 26 | int j = i + textrange.getStartOffset(); 27 | if (j < textrange.getStartOffset()) 28 | j = textrange.getStartOffset(); 29 | if (j > textrange.getEndOffset()) 30 | j = textrange.getEndOffset(); 31 | return j; 32 | } 33 | 34 | public boolean isOneLine() { 35 | return false; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/injection/JFlexJavaInjector.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.injection; 2 | 3 | import com.intellij.lang.StdLanguages; 4 | import com.intellij.openapi.util.TextRange; 5 | import com.intellij.psi.InjectedLanguagePlaces; 6 | import com.intellij.psi.LanguageInjector; 7 | import com.intellij.psi.PsiLanguageInjectionHost; 8 | import org.intellij.lang.jflex.options.JFlexSettings; 9 | import org.intellij.lang.jflex.psi.JFlexElement; 10 | import org.intellij.lang.jflex.psi.JFlexJavaCode; 11 | import org.intellij.lang.jflex.psi.JFlexPsiFile; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | public class JFlexJavaInjector implements LanguageInjector { 15 | 16 | public static final String DEFCLASS = "Yylex"; 17 | public static final String DEFTYPE = "int"; 18 | 19 | private JFlexSettings settings; 20 | 21 | public JFlexJavaInjector() { 22 | settings = JFlexSettings.getInstance(); 23 | } 24 | 25 | public void getLanguagesToInject(@NotNull PsiLanguageInjectionHost _host, @NotNull InjectedLanguagePlaces registrar) { 26 | 27 | if (_host instanceof JFlexJavaCode) { 28 | 29 | if (!settings.ENABLED_EMBED_JAVA) return; 30 | 31 | JFlexJavaCode host = (JFlexJavaCode) _host; 32 | 33 | assert host.getContainingFile() instanceof JFlexPsiFile; 34 | JFlexPsiFile file = (JFlexPsiFile) host.getContainingFile(); 35 | 36 | JFlexJavaCode importSection = file.getImports(); 37 | //processing imports and package section 38 | if (importSection == host) { 39 | registrar.addPlace(StdLanguages.JAVA, new TextRange(0, host.getTextLength()), null, "\npublic class a{}"); 40 | return; 41 | } 42 | 43 | StringBuilder prefix = new StringBuilder(); 44 | 45 | //let's add some imports and package statements from flex file header 46 | if (importSection != null) { 47 | prefix.append(importSection.getText()); 48 | } 49 | 50 | String classnamestr = DEFCLASS; 51 | JFlexElement classname = file.getClassname(); 52 | if (classname != null) { 53 | classnamestr = classname.getText(); 54 | } 55 | 56 | String returntypestr = DEFTYPE; 57 | JFlexElement returntype = file.getReturnType(); 58 | if (returntype != null) { 59 | returntypestr = returntype.getText(); 60 | } 61 | 62 | StringBuilder implementedstr = new StringBuilder(); 63 | JFlexElement[] implemented = file.getImplementedInterfaces(); 64 | //what a lousy piece of code. 65 | if (implemented.length > 0) { 66 | implementedstr.append(" implements "); 67 | for (int i = 0; i < implemented.length; i++) { 68 | JFlexElement jFlexElement = implemented[i]; 69 | implementedstr.append(jFlexElement.getText()); 70 | if (i < implemented.length - 1) { 71 | implementedstr.append(","); 72 | } 73 | } 74 | } 75 | 76 | prefix.append("\npublic class ").append(classnamestr).append(implementedstr.toString()).append("{"); 77 | 78 | StringBuilder suffix = new StringBuilder(); 79 | 80 | if (host.isMatchAction()) { 81 | prefix.append("public ").append(returntypestr).append(" yylex(){"); 82 | suffix.append("}}"); 83 | } else { 84 | suffix.append("}"); 85 | } 86 | 87 | registrar.addPlace(StdLanguages.JAVA, new TextRange(0, host.getTextLength()), prefix.toString(), suffix.toString()); 88 | 89 | } 90 | 91 | } 92 | } -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/lexer/JFlex.flex: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.lexer; 2 | 3 | import com.intellij.lexer.FlexLexer; 4 | import com.intellij.psi.tree.IElementType; 5 | import org.intellij.lang.jflex.JFlexElementTypes; 6 | 7 | %% 8 | 9 | %class _JFlexLexer 10 | %implements FlexLexer 11 | %final 12 | %unicode 13 | %function advance 14 | %type IElementType 15 | %eof{ return; 16 | %eof} 17 | 18 | %{ 19 | private int braceCounter = 0; 20 | %} 21 | 22 | SectionSeparator = "%%" 23 | 24 | LineTerminator = \r|\n|\r\n 25 | InputCharacter = [^\r\n] 26 | WhiteSpace = [ \t] 27 | AnySpace = {LineTerminator} | {WhiteSpace} | [\f] 28 | 29 | EscapedCharacter = \\{InputCharacter} 30 | 31 | Comment = {TraditionalComment} | {DocumentationComment} | {LineComment} 32 | 33 | TraditionalComment = "/*" [^*] ~"*/" | "/*" "*"+ "/" 34 | DocumentationComment = "/**" {CommentContent} "*"+ "/" 35 | CommentContent = ( [^*] | \*+ [^/*] )* 36 | LineComment = {WhiteSpace}* "//" .* 37 | 38 | JavaCodeEndOption = "%}" | "%init}" | "%eof}" | "%eofval}" 39 | 40 | Identifier = [:jletter:] [:jletterdigit:]* 41 | IdentifierReference = \{ {Identifier} \} 42 | 43 | StringLiteral = \" ( \\\" | [^\"\n\r] )* \" 44 | 45 | RegExpPrefix = [\!\~] 46 | RegExpPostfix = [\*\+\?] 47 | 48 | %state OPTIONS_AND_DECLARATIONS, LEXICAL_RULES 49 | 50 | %state IDENTIFIER, IDENTIFIER_REGEXP_LITERAL, IDENTIFIER_REGEXP, IDENTIFIER_REGEXP_IDENTIFIER, IDENTIFIER_REGEXP_CLASS 51 | %state OPTION, OPT_ERROR, OPT_PARAM, OPT_PARAMS, OPT_CODE, OPT_JAVA_CODE, OPT_EXCEPTION, OPT_BOOLEAN 52 | %state STATE, RULE, ACTION_REGEXP, ACTION_REGEXP_IDENTIFIER, ACTION_REGEXP_CLASS, ACTION, ACTION_JAVA_CODE 53 | 54 | %% 55 | 56 | { 57 | {SectionSeparator} { yybegin(OPTIONS_AND_DECLARATIONS); return JFlexElementTypes.SECTION_SIGN; } 58 | {AnySpace}+ { yybegin(YYINITIAL); return JFlexElementTypes.JAVA_CODE; } 59 | . { yybegin(YYINITIAL); return JFlexElementTypes.JAVA_CODE; } 60 | } 61 | 62 | { 63 | {AnySpace}+ { yybegin(OPTIONS_AND_DECLARATIONS); return JFlexElementTypes.WHITE_SPACE; } 64 | {Comment} { yybegin(OPTIONS_AND_DECLARATIONS); return JFlexElementTypes.COMMENT; } 65 | 66 | {SectionSeparator} { yybegin(LEXICAL_RULES); return JFlexElementTypes.SECTION_SIGN; } 67 | "%" { yybegin(OPTION); return JFlexElementTypes.OPTION_SIGN;} 68 | {Identifier} { yybegin(IDENTIFIER); return JFlexElementTypes.MACROS; } 69 | . { yybegin(OPTIONS_AND_DECLARATIONS); return JFlexElementTypes.BAD_CHARACTER; } 70 | } 71 | 72 | { 73 | {AnySpace}+ { yybegin(LEXICAL_RULES); return JFlexElementTypes.WHITE_SPACE; } 74 | {Comment} { yybegin(LEXICAL_RULES); return JFlexElementTypes.COMMENT; } 75 | "<" { yybegin(STATE); return JFlexElementTypes.STATE_LEFT_ANGLE_BRACKET; } 76 | . { yybegin(ACTION_REGEXP); yypushback(yylength()); } 77 | } 78 | 79 | { 80 | {WhiteSpace}+ { yybegin(IDENTIFIER); return JFlexElementTypes.WHITE_SPACE; } 81 | "=" { yybegin(IDENTIFIER_REGEXP_LITERAL); return JFlexElementTypes.EQ; } 82 | . { yybegin(OPTIONS_AND_DECLARATIONS); return JFlexElementTypes.BAD_CHARACTER; } 83 | } 84 | { 85 | {WhiteSpace}+ { yybegin(IDENTIFIER_REGEXP_LITERAL); return JFlexElementTypes.WHITE_SPACE; } 86 | . { yybegin(IDENTIFIER_REGEXP); yypushback(yylength()); } 87 | } 88 | { 89 | {LineTerminator}+ { yybegin(OPTIONS_AND_DECLARATIONS); return JFlexElementTypes.WHITE_SPACE; } 90 | {WhiteSpace}+ { yybegin(IDENTIFIER_REGEXP); return JFlexElementTypes.REGEXP_WHITE_SPACE; } 91 | {EscapedCharacter} { yybegin(IDENTIFIER_REGEXP); return JFlexElementTypes.REGEXP_SYMBOL; } 92 | "[" { yybegin(IDENTIFIER_REGEXP_CLASS); return JFlexElementTypes.REGEXP_LEFT_BRACKET;} 93 | "|" { yybegin(IDENTIFIER_REGEXP); return JFlexElementTypes.REGEXP_OR; } 94 | "(" { yybegin(IDENTIFIER_REGEXP); return JFlexElementTypes.REGEXP_LEFT_PARENTHESIS; } 95 | ")" { yybegin(IDENTIFIER_REGEXP); return JFlexElementTypes.REGEXP_RIGHT_PARENTHESIS; } 96 | "{" { yybegin(IDENTIFIER_REGEXP_IDENTIFIER); return JFlexElementTypes.REGEXP_LEFT_BRACE; } 97 | {RegExpPrefix} { yybegin(IDENTIFIER_REGEXP); return JFlexElementTypes.REGEXP_PREFIX; } 98 | {RegExpPostfix} { yybegin(IDENTIFIER_REGEXP); return JFlexElementTypes.REGEXP_POSTFIX; } 99 | {StringLiteral} { yybegin(IDENTIFIER_REGEXP); return JFlexElementTypes.REGEXP_STRING_LITERAL; } 100 | . { yybegin(IDENTIFIER_REGEXP); return JFlexElementTypes.REGEXP_SYMBOL; } 101 | } 102 | { 103 | {LineTerminator}+ { yybegin(OPTIONS_AND_DECLARATIONS); return JFlexElementTypes.WHITE_SPACE; } 104 | {Identifier} { yybegin(IDENTIFIER_REGEXP_IDENTIFIER); return JFlexElementTypes.REGEXP_MACROS_REF; } 105 | "}" { yybegin(IDENTIFIER_REGEXP); return JFlexElementTypes.REGEXP_RIGHT_BRACE; } 106 | . { yybegin(IDENTIFIER_REGEXP); return JFlexElementTypes.BAD_CHARACTER; } 107 | } 108 | { 109 | {LineTerminator}+ { yybegin(OPTIONS_AND_DECLARATIONS); return JFlexElementTypes.WHITE_SPACE; } 110 | {EscapedCharacter} { yybegin(IDENTIFIER_REGEXP_CLASS); return JFlexElementTypes.REGEXP_CLASS_SYMBOL; } 111 | "]" { yybegin(IDENTIFIER_REGEXP); return JFlexElementTypes.REGEXP_RIGHT_BRACKET;} 112 | {StringLiteral} { yybegin(IDENTIFIER_REGEXP_CLASS); return JFlexElementTypes.REGEXP_STRING_LITERAL; } 113 | . { yybegin(IDENTIFIER_REGEXP_CLASS); return JFlexElementTypes.REGEXP_CLASS_SYMBOL; } 114 | } 115 | 116 |