├── .gitignore ├── icons └── fileTypes │ └── jflex.png ├── src └── main │ ├── java │ └── org │ │ └── intellij │ │ └── lang │ │ └── jflex │ │ ├── psi │ │ ├── JFlexStatement.java │ │ ├── JFlexExpression.java │ │ ├── JFlexElement.java │ │ ├── JFlexRegexp.java │ │ ├── JFlexClassStatement.java │ │ ├── JFlexTypeStatement.java │ │ ├── JFlexMacroReference.java │ │ ├── JFlexStateReference.java │ │ ├── JFlexStateDefinition.java │ │ ├── JFlexStateStatement.java │ │ ├── JFlexJavaCode.java │ │ ├── JFlexImplementsStatement.java │ │ ├── JFlexMacroDefinition.java │ │ ├── JFlexSection.java │ │ ├── JFlexOptionStatement.java │ │ ├── JFlexElementVisitor.java │ │ ├── impl │ │ │ ├── JFlexStatementImpl.java │ │ │ ├── JFlexExpressionImpl.java │ │ │ ├── JFlexRegexpImpl.java │ │ │ ├── JFlexSectionImpl.java │ │ │ ├── JFlexTypeStatementImpl.java │ │ │ ├── JFlexClassStatementImpl.java │ │ │ ├── JFlexStateDefinitionImpl.java │ │ │ ├── JFlexOptionStatementBase.java │ │ │ ├── JFlexImplementsStatementImpl.java │ │ │ ├── JFlexStateStatementImpl.java │ │ │ ├── JFlexElementImpl.java │ │ │ ├── JFlexMacroDefinitionImpl.java │ │ │ ├── JFlexJavaCodeImpl.java │ │ │ ├── JFlexStateReferenceImpl.java │ │ │ ├── JFlexMacroReferenceImpl.java │ │ │ └── JFlexPsiFileImpl.java │ │ └── JFlexPsiFile.java │ │ ├── lexer │ │ ├── JFlexParsingLexer.java │ │ ├── JFlexHighlighterLexer.java │ │ ├── JFlexMergingLexer.java │ │ ├── JFlex.flex │ │ └── _JFlexLexer.java │ │ ├── fileTypes │ │ ├── JFlexFileTypeFactory.java │ │ ├── JFlexFileType.java │ │ └── JFlexSyntaxHighlighter.java │ │ ├── util │ │ ├── JFlexBundle.java │ │ └── JFlexBundle.properties │ │ ├── compiler │ │ ├── JFlexCompilerFactory.java │ │ ├── JFlexMessage.java │ │ ├── JFlex.java │ │ └── JFlexSourceGeneratingCompiler.java │ │ ├── JFlexCommenter.java │ │ ├── validation │ │ └── JFlexAnnotatingVisitor.java │ │ ├── JFlexElementType.java │ │ ├── JFlexLanguage.java │ │ ├── injection │ │ ├── EmbeddedJavaLiteralTextEscaper.java │ │ └── JFlexJavaInjector.java │ │ ├── options │ │ ├── JFlexConfigurable.java │ │ ├── JFlexSettings.java │ │ ├── JFlexSettingsForm.form │ │ └── JFlexSettingsForm.java │ │ ├── JFlexDocumentationProvider.java │ │ ├── JFlexFindUsagesProvider.java │ │ ├── parser │ │ ├── JFlexParserDefinition.java │ │ └── JFlexParser.java │ │ ├── editor │ │ ├── JFlexHighlighterColors.java │ │ └── colors │ │ │ └── JFlexColorPage.java │ │ └── JFlexElementTypes.java │ └── resources │ └── META-INF │ └── plugin.xml ├── README.md ├── .travis.yml └── LICENSE.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | build/ 4 | out/ 5 | gradle/ 6 | gradlew 7 | gradle.bat 8 | 9 | -------------------------------------------------------------------------------- /icons/fileTypes/jflex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jflex-de/idea-jflex/HEAD/icons/fileTypes/jflex.png -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/JFlexStatement.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi; 2 | 3 | /** 4 | * JFlex statement 5 | * 6 | * @author Alexey Efimov 7 | */ 8 | public interface JFlexStatement extends JFlexElement { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/JFlexExpression.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi; 2 | 3 | /** 4 | * JFlex expression. 5 | * 6 | * @author Alexey Efimov 7 | */ 8 | public interface JFlexExpression extends JFlexElement { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/lexer/JFlexParsingLexer.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.lexer; 2 | 3 | /** 4 | * Lexer adapter. 5 | * 6 | * @author Alexey Efimov 7 | */ 8 | public class JFlexParsingLexer extends JFlexMergingLexer { 9 | 10 | } -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/lexer/JFlexHighlighterLexer.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.lexer; 2 | 3 | /** 4 | * Lexer adapter. 5 | * 6 | * @author Alexey Efimov 7 | */ 8 | public class JFlexHighlighterLexer extends JFlexMergingLexer { 9 | 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/JFlexElement.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi; 2 | 3 | import com.intellij.psi.PsiElement; 4 | 5 | /** 6 | * Marker. 7 | * 8 | * @author Alexey Efimov 9 | */ 10 | public interface JFlexElement extends PsiElement { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/JFlexRegexp.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: Max 6 | * Date: 22.03.2008 7 | * Time: 23:18:34 8 | */ 9 | public interface JFlexRegexp extends JFlexElement { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/JFlexClassStatement.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi; 2 | 3 | /** 4 | * The JFlex "%class _MyLexer" statement 5 | * 6 | * @author Alexey Efimov 7 | */ 8 | public interface JFlexClassStatement extends JFlexOptionStatement { 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/JFlexTypeStatement.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: Max 6 | * Date: 17.03.2008 7 | * Time: 23:15:45 8 | */ 9 | public interface JFlexTypeStatement extends JFlexOptionStatement { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/JFlexMacroReference.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi; 2 | 3 | import com.intellij.psi.PsiReference; 4 | 5 | /** 6 | * Created by IntelliJ IDEA. 7 | * User: Max 8 | * Date: 19.03.2008 9 | * Time: 23:21:39 10 | */ 11 | public interface JFlexMacroReference extends JFlexElement, PsiReference { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/JFlexStateReference.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi; 2 | 3 | import com.intellij.psi.PsiReference; 4 | 5 | /** 6 | * Created by IntelliJ IDEA. 7 | * User: Max 8 | * Date: 28.03.2008 9 | * Time: 9:10:57 10 | */ 11 | public interface JFlexStateReference extends JFlexElement, PsiReference { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/JFlexStateDefinition.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi; 2 | 3 | import com.intellij.psi.PsiNamedElement; 4 | 5 | /** 6 | * Created by IntelliJ IDEA. 7 | * User: Max 8 | * Date: 24.03.2008 9 | * Time: 23:33:09 10 | */ 11 | public interface JFlexStateDefinition extends JFlexElement, PsiNamedElement { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/JFlexStateStatement.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: Max 6 | * Date: 24.03.2008 7 | * Time: 23:43:18 8 | */ 9 | public interface JFlexStateStatement extends JFlexElement { 10 | 11 | public JFlexStateDefinition[] getStateDefinitions(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/JFlexJavaCode.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi; 2 | 3 | import com.intellij.psi.PsiLanguageInjectionHost; 4 | 5 | /** 6 | * Created by IntelliJ IDEA. 7 | * User: Max 8 | * Date: 15.03.2008 9 | * Time: 18:52:38 10 | */ 11 | public interface JFlexJavaCode extends JFlexElement, PsiLanguageInjectionHost { 12 | 13 | public boolean isMatchAction(); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/JFlexImplementsStatement.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: Max 6 | * Date: 18.03.2008 7 | * Time: 22:53:00 8 | */ 9 | 10 | /** 11 | * %implements "interface 1"[, "interface 2", ..] 12 | */ 13 | public interface JFlexImplementsStatement extends JFlexElement { 14 | 15 | public JFlexExpression[] getInterfaces(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/JFlexMacroDefinition.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi; 2 | 3 | import com.intellij.psi.PsiElement; 4 | import com.intellij.psi.PsiNamedElement; 5 | 6 | /** 7 | * Created by IntelliJ IDEA. 8 | * User: Max 9 | * Date: 20.03.2008 10 | * Time: 22:42:53 11 | */ 12 | public interface JFlexMacroDefinition extends JFlexElement, PsiNamedElement { 13 | 14 | PsiElement getNameElement(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/JFlexSection.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi; 2 | 3 | /** 4 | * Created by IntelliJ IDEA. 5 | * User: Max 6 | * Date: 18.03.2008 7 | * Time: 22:55:17 8 | */ 9 | 10 | /** 11 | * There are three sections in JFlex spec file:
12 | * UserCode
13 | * %%
14 | * Options and declarations
15 | * %%
16 | * Lexical rules
17 | *
18 | */ 19 | public interface JFlexSection extends JFlexElement { 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/JFlexOptionStatement.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | 5 | /** 6 | * Created by IntelliJ IDEA. 7 | * User: Max 8 | * Date: 17.03.2008 9 | * Time: 23:23:12 10 | */ 11 | 12 | /** 13 | * "Class options and user class code" section statement 14 | */ 15 | public interface JFlexOptionStatement extends JFlexStatement { 16 | 17 | @Nullable 18 | public JFlexExpression getValue(); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/JFlexElementVisitor.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi; 2 | 3 | import com.intellij.psi.PsiElementVisitor; 4 | import com.intellij.psi.PsiReferenceExpression; 5 | 6 | /** 7 | * Element visitor. 8 | * 9 | * @author Alexey Efimov 10 | */ 11 | public class JFlexElementVisitor extends PsiElementVisitor { 12 | 13 | // public void visitReferenceExpression(PsiReferenceExpression expression) { 14 | // visitExpression(expression); 15 | // } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/impl/JFlexStatementImpl.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi.impl; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.intellij.lang.jflex.psi.JFlexStatement; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * JFlex statement implementation 9 | * 10 | * @author Alexey Efimov 11 | */ 12 | public class JFlexStatementImpl extends JFlexElementImpl implements JFlexStatement { 13 | public JFlexStatementImpl(@NotNull ASTNode node) { 14 | super(node); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/impl/JFlexExpressionImpl.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi.impl; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.intellij.lang.jflex.psi.JFlexExpression; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * JFlex expression implmentation. 9 | * 10 | * @author Alexey Efimov 11 | */ 12 | public class JFlexExpressionImpl extends JFlexElementImpl implements JFlexExpression { 13 | 14 | public JFlexExpressionImpl(@NotNull ASTNode node) { 15 | super(node); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/impl/JFlexRegexpImpl.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi.impl; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.intellij.lang.jflex.psi.JFlexRegexp; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * Created by IntelliJ IDEA. 9 | * User: Max 10 | * Date: 22.03.2008 11 | * Time: 23:18:54 12 | */ 13 | public class JFlexRegexpImpl extends JFlexElementImpl implements JFlexRegexp { 14 | 15 | public JFlexRegexpImpl(@NotNull ASTNode node) { 16 | super(node); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/impl/JFlexSectionImpl.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi.impl; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.intellij.lang.jflex.psi.JFlexSection; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * Created by IntelliJ IDEA. 9 | * User: Max 10 | * Date: 19.03.2008 11 | * Time: 22:45:06 12 | */ 13 | public class JFlexSectionImpl extends JFlexElementImpl implements JFlexSection { 14 | 15 | public JFlexSectionImpl(@NotNull ASTNode node) { 16 | super(node); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/impl/JFlexTypeStatementImpl.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi.impl; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.intellij.lang.jflex.psi.JFlexTypeStatement; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * Created by IntelliJ IDEA. 9 | * User: Max 10 | * Date: 17.03.2008 11 | * Time: 23:19:57 12 | */ 13 | public class JFlexTypeStatementImpl extends JFlexOptionStatementBase implements JFlexTypeStatement { 14 | 15 | public JFlexTypeStatementImpl(@NotNull ASTNode node) { 16 | super(node); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /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/psi/JFlexPsiFile.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | 5 | /** 6 | * Created by IntelliJ IDEA. 7 | * User: Max 8 | * Date: 17.03.2008 9 | * Time: 2:18:18 10 | */ 11 | public interface JFlexPsiFile extends JFlexElement { 12 | 13 | @Nullable 14 | JFlexElement getClassname(); 15 | 16 | @Nullable 17 | JFlexElement getReturnType(); 18 | 19 | JFlexExpression[] getImplementedInterfaces(); 20 | 21 | JFlexMacroDefinition[] getDeclaredMacroses(); 22 | 23 | JFlexStateStatement[] getStateStatements(); 24 | 25 | @Nullable 26 | JFlexJavaCode getImports(); 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/lexer/JFlexMergingLexer.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.lexer; 2 | 3 | import com.intellij.lexer.FlexAdapter; 4 | import com.intellij.lexer.MergingLexerAdapter; 5 | import com.intellij.psi.tree.TokenSet; 6 | import org.intellij.lang.jflex.JFlexElementTypes; 7 | 8 | /** 9 | * Created by IntelliJ IDEA. 10 | * User: Max 11 | * Date: 15.03.2008 12 | * Time: 15:36:05 13 | */ 14 | public class JFlexMergingLexer extends MergingLexerAdapter { 15 | 16 | public static final TokenSet mergeme = TokenSet.create(JFlexElementTypes.JAVA_CODE); 17 | 18 | public JFlexMergingLexer() { 19 | 20 | super(new FlexAdapter(new _JFlexLexer((java.io.Reader) null)), mergeme); 21 | 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/impl/JFlexClassStatementImpl.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi.impl; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.intellij.lang.jflex.psi.JFlexClassStatement; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * Implementation of JFlex class statement. 9 | * 10 | * @author Alexey Efimov 11 | */ 12 | public class JFlexClassStatementImpl extends JFlexOptionStatementBase implements JFlexClassStatement { 13 | 14 | public JFlexClassStatementImpl(@NotNull ASTNode node) { 15 | super(node); 16 | } 17 | 18 | public String toString() { 19 | return super.toString(); //To change body of overridden methods use File | Settings | File Templates. 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/util/JFlexBundle.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.util; 2 | 3 | import com.intellij.CommonBundle; 4 | import org.jetbrains.annotations.NonNls; 5 | import org.jetbrains.annotations.PropertyKey; 6 | 7 | import java.util.ResourceBundle; 8 | 9 | public final class JFlexBundle { 10 | @NonNls 11 | private static final String BUNDLE_NAME = "org.intellij.lang.jflex.util.JFlexBundle"; 12 | private static final ResourceBundle BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME); 13 | 14 | private JFlexBundle() { 15 | } 16 | 17 | public static String message(@PropertyKey(resourceBundle = BUNDLE_NAME)String key, Object... params) { 18 | return CommonBundle.message(BUNDLE, key, params); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /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/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/validation/JFlexAnnotatingVisitor.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.validation; 2 | 3 | import com.intellij.lang.annotation.AnnotationHolder; 4 | import com.intellij.lang.annotation.Annotator; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.PsiElementVisitor; 7 | import com.intellij.psi.PsiReferenceExpression; 8 | import org.intellij.lang.jflex.psi.JFlexMacroReference; 9 | 10 | /** 11 | * Created by IntelliJ IDEA. 12 | * User: Max 13 | * Date: 22.03.2008 14 | * Time: 17:19:55 15 | */ 16 | public class JFlexAnnotatingVisitor extends PsiElementVisitor implements Annotator { 17 | 18 | public void annotate(PsiElement psiElement, AnnotationHolder holder) { 19 | psiElement.accept(this); 20 | } 21 | 22 | public void visitReferenceExpression(PsiReferenceExpression expression) { 23 | } 24 | 25 | public void visitMacroReference(JFlexMacroReference expression) { 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/impl/JFlexStateDefinitionImpl.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi.impl; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.psi.PsiElement; 5 | import com.intellij.util.IncorrectOperationException; 6 | import org.intellij.lang.jflex.psi.JFlexStateDefinition; 7 | import org.jetbrains.annotations.NonNls; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | /** 11 | * Created by IntelliJ IDEA. 12 | * User: Max 13 | * Date: 24.03.2008 14 | * Time: 23:34:47 15 | */ 16 | public class JFlexStateDefinitionImpl extends JFlexElementImpl implements JFlexStateDefinition { 17 | 18 | public JFlexStateDefinitionImpl(@NotNull ASTNode node) { 19 | super(node); 20 | } 21 | 22 | public String getName() { 23 | return getText(); 24 | } 25 | 26 | public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException { 27 | throw new IncorrectOperationException(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /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/psi/impl/JFlexOptionStatementBase.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi.impl; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.intellij.lang.jflex.JFlexElementTypes; 5 | import org.intellij.lang.jflex.psi.JFlexExpression; 6 | import org.intellij.lang.jflex.psi.JFlexOptionStatement; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | /** 11 | * Created by IntelliJ IDEA. 12 | * User: Max 13 | * Date: 17.03.2008 14 | * Time: 23:21:47 15 | */ 16 | public abstract class JFlexOptionStatementBase extends JFlexElementImpl implements JFlexOptionStatement { 17 | 18 | public JFlexOptionStatementBase(@NotNull ASTNode node) { 19 | super(node); 20 | } 21 | 22 | @Nullable 23 | public JFlexExpression getValue() { 24 | final ASTNode node = getNode().findChildByType(JFlexElementTypes.EXPRESSIONS); 25 | return (JFlexExpression) (node != null ? node.getPsi() : null); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /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/psi/impl/JFlexImplementsStatementImpl.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi.impl; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import org.intellij.lang.jflex.JFlexElementTypes; 5 | import org.intellij.lang.jflex.psi.JFlexExpression; 6 | import org.intellij.lang.jflex.psi.JFlexImplementsStatement; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * Created by IntelliJ IDEA. 11 | * User: Max 12 | * Date: 18.03.2008 13 | * Time: 23:53:42 14 | */ 15 | public class JFlexImplementsStatementImpl extends JFlexElementImpl implements JFlexImplementsStatement { 16 | 17 | public JFlexImplementsStatementImpl(@NotNull ASTNode node) { 18 | super(node); 19 | } 20 | 21 | public JFlexExpression[] getInterfaces() { 22 | ASTNode[] nodes = getNode().getChildren(JFlexElementTypes.EXPRESSIONS); 23 | JFlexExpression[] result = new JFlexExpression[nodes.length]; 24 | int i = 0; 25 | for (ASTNode node : nodes) { 26 | result[i++] = (JFlexExpression) node.getPsi(); 27 | } 28 | return result; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/impl/JFlexStateStatementImpl.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi.impl; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.psi.tree.TokenSet; 5 | import org.intellij.lang.jflex.JFlexElementTypes; 6 | import org.intellij.lang.jflex.psi.JFlexStateDefinition; 7 | import org.intellij.lang.jflex.psi.JFlexStateStatement; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | /** 11 | * Created by IntelliJ IDEA. 12 | * User: Max 13 | * Date: 24.03.2008 14 | * Time: 23:44:01 15 | */ 16 | public class JFlexStateStatementImpl extends JFlexElementImpl implements JFlexStateStatement { 17 | 18 | public static final TokenSet STATEDEF = TokenSet.create(JFlexElementTypes.STATE_DEFINITION); 19 | 20 | public JFlexStateStatementImpl(@NotNull ASTNode node) { 21 | super(node); 22 | } 23 | 24 | public JFlexStateDefinition[] getStateDefinitions() { 25 | ASTNode[] states = getNode().getChildren(STATEDEF); 26 | JFlexStateDefinition[] result = new JFlexStateDefinition[states.length]; 27 | for (int i = 0; i < states.length; i++) { 28 | result[i] = (JFlexStateDefinition) states[i].getPsi(); 29 | } 30 | return result; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /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/psi/impl/JFlexElementImpl.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi.impl; 2 | 3 | import com.intellij.extapi.psi.ASTWrapperPsiElement; 4 | import com.intellij.lang.ASTNode; 5 | import com.intellij.lang.Language; 6 | import org.intellij.lang.jflex.JFlexLanguage; 7 | import org.intellij.lang.jflex.psi.JFlexElement; 8 | import org.jetbrains.annotations.NonNls; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | /** 12 | * JFlex base element. 13 | * 14 | * @author Alexey Efimov 15 | */ 16 | public class JFlexElementImpl extends ASTWrapperPsiElement implements JFlexElement { 17 | 18 | @NonNls 19 | private static final String IMPL = "Impl"; 20 | 21 | public JFlexElementImpl(@NotNull ASTNode node) { 22 | super(node); 23 | } 24 | 25 | @NotNull 26 | public Language getLanguage() { 27 | return JFlexLanguage.LANGUAGE; 28 | } 29 | 30 | public String toString() { 31 | String classname = getClass().getName(); 32 | if (classname.endsWith(IMPL)) { 33 | classname = classname.substring(0, classname.length() - IMPL.length()); 34 | } 35 | 36 | classname = classname.substring(classname.lastIndexOf(".") + 1); 37 | return classname; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/util/JFlexBundle.properties: -------------------------------------------------------------------------------- 1 | jflex.filetype.description=JFlex files 2 | jflex=JFlex 3 | jflex.settings=JFlex settings 4 | enabled.jflex.files.compilation=&Enable JFlex files compilation 5 | jflex.compiler.settings=JFlex compiler settings 6 | path.to.jflex=&Path to JFlex: 7 | skeleton.file=&Skeleton file: 8 | command.line.options=Command line &options: 9 | enabled.embed.java.code.support=Embedded &Java code support (turn it off if you feel it's too slow) 10 | select.jflex.home=Select JFlex home 11 | please.select.jflex.folder=Please, select JFlex folder 12 | select.skeleton.file=Select skeleton file 13 | please.select.jflex.skeleton.file=Please, select JFlex skeleton file 14 | please.enter.path.to.jflex.home.directory=Please, enter path to JFlex home directory 15 | jflex.home.path.is.invalid=JFlex home path is invalid 16 | jflex.skeleton.file.was.not.found=JFlex skeleton file was not found 17 | file.not.generated=File not generated 18 | command.0.execution.failed.with.exit.code.1=Command \"{0}\" execution failed with exit code {1} 19 | jar.not.found=JFlex jar file not found in configured path (\"{0}\") 20 | 21 | 22 | parser.comma.expected=Comma expected 23 | parser.expression.expected=Expression expected 24 | parser.eq.expected="=" expected 25 | parser.macrovalue.expected=Macro value expected 26 | -------------------------------------------------------------------------------- /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/psi/impl/JFlexMacroDefinitionImpl.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi.impl; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.psi.PsiElement; 5 | import com.intellij.util.IncorrectOperationException; 6 | import org.intellij.lang.jflex.JFlexElementTypes; 7 | import org.intellij.lang.jflex.psi.JFlexMacroDefinition; 8 | import org.jetbrains.annotations.NonNls; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | /** 12 | * Created by IntelliJ IDEA. 13 | * User: Max 14 | * Date: 20.03.2008 15 | * Time: 22:45:46 16 | */ 17 | public class JFlexMacroDefinitionImpl extends JFlexElementImpl implements JFlexMacroDefinition { 18 | 19 | public JFlexMacroDefinitionImpl(@NotNull ASTNode node) { 20 | super(node); 21 | } 22 | 23 | public ASTNode findNameElement() { 24 | return getNode().findChildByType(JFlexElementTypes.MACROS); 25 | } 26 | 27 | public PsiElement getNameElement() { 28 | ASTNode node = findNameElement(); 29 | return node != null ? node.getPsi() : null; 30 | } 31 | 32 | public String getName() { 33 | ASTNode node = findNameElement(); 34 | return node != null ? node.getText() : null; 35 | } 36 | 37 | public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException { 38 | throw new IncorrectOperationException(); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /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/options/JFlexConfigurable.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.options; 2 | 3 | import javax.swing.*; 4 | 5 | import com.intellij.openapi.options.Configurable; 6 | import com.intellij.openapi.options.ConfigurationException; 7 | import org.intellij.lang.jflex.util.JFlexBundle; 8 | import org.jetbrains.annotations.Nls; 9 | import org.jetbrains.annotations.NonNls; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | /** 13 | * Configurable for JFlex. 14 | * 15 | * @author Alexey Efimov 16 | */ 17 | public final class JFlexConfigurable implements Configurable { 18 | private JFlexSettingsForm settingsForm; 19 | 20 | @Nls 21 | public String getDisplayName() { 22 | return JFlexBundle.message("jflex"); 23 | } 24 | 25 | @Nullable 26 | public Icon getIcon() { 27 | return null; 28 | } 29 | 30 | @Nullable 31 | @NonNls 32 | public String getHelpTopic() { 33 | return null; 34 | } 35 | 36 | public JComponent createComponent() { 37 | if (settingsForm == null) { 38 | settingsForm = new JFlexSettingsForm(JFlexSettings.getInstance()); 39 | } 40 | return settingsForm.getFormComponent(); 41 | } 42 | 43 | public boolean isModified() { 44 | return settingsForm != null && settingsForm.isModified(JFlexSettings.getInstance()); 45 | } 46 | 47 | public void apply() throws ConfigurationException { 48 | if (settingsForm != null) { 49 | JFlexSettings.getInstance().loadState(settingsForm.getState()); 50 | } 51 | } 52 | 53 | public void reset() { 54 | if (settingsForm != null) { 55 | settingsForm.loadState(JFlexSettings.getInstance()); 56 | } 57 | } 58 | 59 | public void disposeUIResources() { 60 | settingsForm = null; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /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/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/options/JFlexSettings.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.options; 2 | 3 | import com.intellij.openapi.application.ApplicationManager; 4 | import com.intellij.openapi.application.PathManager; 5 | import com.intellij.openapi.components.*; 6 | import com.intellij.util.xmlb.XmlSerializerUtil; 7 | import org.intellij.lang.jflex.util.JFlexBundle; 8 | import org.jetbrains.annotations.NonNls; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.io.File; 12 | 13 | /** 14 | * Options of JFlex. 15 | * 16 | * @author Alexey Efimov 17 | */ 18 | @State(name = "JFlexSettings", storages = {@Storage(file = "$APP_CONFIG$/jflex.xml")}) 19 | public final class JFlexSettings implements PersistentStateComponent { 20 | @NonNls 21 | static final String TOOLS_DIR = "tools"; 22 | @NonNls 23 | static final String IDEA_FLEX_SKELETON = "idea-flex.skeleton"; 24 | @NonNls 25 | static final String DEFAULT_OPTIONS_CHARAT_NOBAK = "--charat --nobak"; 26 | 27 | public static JFlexSettings getInstance() { 28 | return ServiceManager.getService(JFlexSettings.class); 29 | } 30 | 31 | public boolean ENABLED_COMPILATION = true; 32 | public String JFLEX_HOME = getDefaultJFlexHome(); 33 | public String SKELETON_PATH = getDefaultSkeletonPath(JFLEX_HOME); 34 | public String COMMAND_LINE_OPTIONS = DEFAULT_OPTIONS_CHARAT_NOBAK; 35 | public boolean ENABLED_EMBED_JAVA = true; 36 | 37 | public JFlexSettings getState() { 38 | return this; 39 | } 40 | 41 | public void loadState(JFlexSettings state) { 42 | XmlSerializerUtil.copyBean(state, this); 43 | } 44 | 45 | 46 | 47 | public static String getDefaultSkeletonPath(String jFlexHome) { 48 | return new File(jFlexHome, IDEA_FLEX_SKELETON).getPath(); 49 | } 50 | 51 | public static String getDefaultJFlexHome() { 52 | return new File(new File(PathManager.getHomePath(), TOOLS_DIR), "jflex").getPath(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/impl/JFlexJavaCodeImpl.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi.impl; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.lang.injection.InjectedLanguageManager; 5 | import com.intellij.openapi.util.Pair; 6 | import com.intellij.openapi.util.TextRange; 7 | import com.intellij.psi.LiteralTextEscaper; 8 | import com.intellij.psi.PsiElement; 9 | import com.intellij.psi.PsiLanguageInjectionHost; 10 | import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; 11 | import org.intellij.lang.jflex.JFlexElementTypes; 12 | import org.intellij.lang.jflex.injection.EmbeddedJavaLiteralTextEscaper; 13 | import org.intellij.lang.jflex.psi.JFlexJavaCode; 14 | import org.jetbrains.annotations.NotNull; 15 | import org.jetbrains.annotations.Nullable; 16 | 17 | import java.util.List; 18 | 19 | /** 20 | * Created by IntelliJ IDEA. 21 | * User: Max 22 | * Date: 15.03.2008 23 | * Time: 18:51:14 24 | */ 25 | public class JFlexJavaCodeImpl extends JFlexElementImpl implements JFlexJavaCode { 26 | 27 | public JFlexJavaCodeImpl(@NotNull ASTNode node) { 28 | super(node); 29 | } 30 | 31 | @Override 32 | public boolean isValidHost() { 33 | return true; 34 | } 35 | 36 | public boolean isMatchAction() { 37 | ASTNode prev = getNode().getTreePrev(); 38 | return prev != null && prev.getElementType() == JFlexElementTypes.LEFT_BRACE; 39 | } 40 | 41 | @Nullable 42 | @Deprecated 43 | public List> getInjectedPsi() { 44 | return InjectedLanguageManager.getInstance(getProject()).getInjectedPsiFiles(this); 45 | } 46 | 47 | public void processInjectedPsi(@NotNull InjectedPsiVisitor visitor) { 48 | InjectedLanguageUtil.enumerate(this, visitor); 49 | } 50 | 51 | public PsiLanguageInjectionHost updateText(@NotNull String text) { 52 | return this; 53 | } 54 | 55 | public void fixText(@NotNull String text) { 56 | } 57 | 58 | @NotNull 59 | public LiteralTextEscaper createLiteralTextEscaper() { 60 | return new EmbeddedJavaLiteralTextEscaper(this); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | JFlex Support 3 | 1.7 4 | Alexey Efimov, Max Ishchenko, Jan Dolecek, Steve Rowe, Régis Décamps 5 | 7 |
  • Update for JFlex 1.7.0. 8 | 9 | 10 | v1.6.1 11 |
      12 |
    • Updated for JFlex 1.6.1 13 |
    • .jflex extension added to JFlex file type. (Steve Rowe) 14 |
    15 | ]]> 16 | 17 | 18 | Enables JFlex support in IntelliJ IDEA. 19 | org.intellij.lang.jflex.util.JFlexBundle 20 | 21 | 22 | 23 | 24 | 26 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/impl/JFlexStateReferenceImpl.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi.impl; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.openapi.util.TextRange; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.PsiReference; 7 | import com.intellij.util.IncorrectOperationException; 8 | import org.intellij.lang.jflex.psi.JFlexPsiFile; 9 | import org.intellij.lang.jflex.psi.JFlexStateDefinition; 10 | import org.intellij.lang.jflex.psi.JFlexStateReference; 11 | import org.intellij.lang.jflex.psi.JFlexStateStatement; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | import java.util.ArrayList; 16 | import java.util.Arrays; 17 | import java.util.List; 18 | 19 | /** 20 | * Created by IntelliJ IDEA. 21 | * User: Max 22 | * Date: 28.03.2008 23 | * Time: 9:11:25 24 | */ 25 | public class JFlexStateReferenceImpl extends JFlexElementImpl implements JFlexStateReference { 26 | 27 | public JFlexStateReferenceImpl(@NotNull ASTNode node) { 28 | super(node); 29 | } 30 | 31 | public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { 32 | throw new IncorrectOperationException(); 33 | } 34 | 35 | public PsiReference getReference() { 36 | return this; 37 | } 38 | 39 | public String getCanonicalText() { 40 | return getText(); 41 | } 42 | 43 | public PsiElement getElement() { 44 | return this; 45 | } 46 | 47 | public TextRange getRangeInElement() { 48 | return new TextRange(0, getTextLength()); 49 | } 50 | 51 | public Object[] getVariants() { 52 | return new Object[0]; 53 | } 54 | 55 | public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException { 56 | throw new IncorrectOperationException(); 57 | } 58 | 59 | public boolean isReferenceTo(PsiElement element) { 60 | return element instanceof JFlexStateDefinition && ((JFlexStateDefinition) element).getName().equals(getText()); 61 | } 62 | 63 | 64 | public boolean isSoft() { 65 | return false; 66 | } 67 | 68 | @Nullable 69 | public PsiElement resolve() { 70 | //todo: do the right way 71 | JFlexPsiFile file = (JFlexPsiFile) this.getContainingFile(); 72 | JFlexStateStatement[] macroses = file.getStateStatements(); 73 | List suspects = new ArrayList(); 74 | for (JFlexStateStatement macros : macroses) { 75 | suspects.addAll(Arrays.asList(macros.getStateDefinitions())); 76 | } 77 | for (JFlexStateDefinition suspect : suspects) { 78 | if (suspect.getName().equals(getText())) { 79 | return suspect; 80 | } 81 | } 82 | return null; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/impl/JFlexMacroReferenceImpl.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi.impl; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.openapi.util.TextRange; 5 | import com.intellij.psi.PsiElement; 6 | import com.intellij.psi.PsiElementVisitor; 7 | import com.intellij.psi.PsiReference; 8 | import com.intellij.psi.search.searches.ReferencesSearch; 9 | import com.intellij.util.IncorrectOperationException; 10 | import com.intellij.util.Query; 11 | import org.intellij.lang.jflex.psi.JFlexMacroDefinition; 12 | import org.intellij.lang.jflex.psi.JFlexMacroReference; 13 | import org.intellij.lang.jflex.psi.JFlexPsiFile; 14 | import org.intellij.lang.jflex.validation.JFlexAnnotatingVisitor; 15 | import org.jetbrains.annotations.NotNull; 16 | import org.jetbrains.annotations.Nullable; 17 | 18 | /** 19 | * Created by IntelliJ IDEA. 20 | * User: Max 21 | * Date: 19.03.2008 22 | * Time: 23:22:03 23 | */ 24 | public class JFlexMacroReferenceImpl extends JFlexElementImpl implements JFlexMacroReference { 25 | 26 | public JFlexMacroReferenceImpl(@NotNull ASTNode node) { 27 | super(node); 28 | } 29 | 30 | public PsiReference getReference() { 31 | return this; 32 | } 33 | 34 | public void accept(@NotNull PsiElementVisitor visitor) { 35 | if (visitor instanceof JFlexAnnotatingVisitor) { 36 | ((JFlexAnnotatingVisitor) visitor).visitMacroReference(this); 37 | } 38 | } 39 | 40 | public PsiElement getElement() { 41 | return this; 42 | } 43 | 44 | public TextRange getRangeInElement() { 45 | return new TextRange(0, getTextLength()); 46 | } 47 | 48 | @Nullable 49 | public PsiElement resolve() { 50 | //Is it the correct way? 51 | JFlexPsiFile file = (JFlexPsiFile) this.getContainingFile(); 52 | JFlexMacroDefinition[] macroses = file.getDeclaredMacroses(); 53 | for (JFlexMacroDefinition m : macroses) { 54 | if (getText().equals(m.getName())) { 55 | return m; 56 | } 57 | } 58 | return null; 59 | } 60 | 61 | public int getTextOffset() { 62 | return super.getTextOffset(); 63 | } 64 | 65 | public String getCanonicalText() { 66 | return getText(); 67 | } 68 | 69 | public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException { 70 | throw new IncorrectOperationException(); 71 | } 72 | 73 | public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { 74 | throw new IncorrectOperationException(); 75 | } 76 | 77 | public boolean isReferenceTo(PsiElement element) { 78 | return element instanceof JFlexMacroDefinition && ((JFlexMacroDefinition) element).getName().equals(getText()); 79 | } 80 | 81 | public Object[] getVariants() { 82 | Query query = ReferencesSearch.search(this); 83 | return query.findAll().toArray(); 84 | } 85 | 86 | public boolean isSoft() { 87 | return false; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/psi/impl/JFlexPsiFileImpl.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.psi.impl; 2 | 3 | import com.intellij.extapi.psi.PsiFileBase; 4 | import com.intellij.lang.ASTNode; 5 | import com.intellij.openapi.fileTypes.FileType; 6 | import com.intellij.psi.FileViewProvider; 7 | import com.intellij.psi.tree.TokenSet; 8 | import org.intellij.lang.jflex.JFlexElementTypes; 9 | import org.intellij.lang.jflex.JFlexLanguage; 10 | import org.intellij.lang.jflex.fileTypes.JFlexFileType; 11 | import org.intellij.lang.jflex.psi.*; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | /** 16 | * JFlex PSI file. 17 | * 18 | * @author Alexey Efimov 19 | */ 20 | public class JFlexPsiFileImpl extends PsiFileBase implements JFlexPsiFile { 21 | 22 | public static final TokenSet MACROSET = TokenSet.create(JFlexElementTypes.MACRO_DEFINITION); 23 | public static final TokenSet STATESTATEMENTSET = TokenSet.create(JFlexElementTypes.STATE_STATEMENT); 24 | 25 | public JFlexPsiFileImpl(FileViewProvider viewProvider) { 26 | super(viewProvider, JFlexLanguage.LANGUAGE); 27 | } 28 | 29 | @Nullable 30 | public JFlexElement getClassname() { 31 | JFlexExpression classexp = null; 32 | ASTNode classnode = getNode().findChildByType(JFlexElementTypes.CLASS_STATEMENT); 33 | if (classnode != null) { 34 | classexp = ((JFlexClassStatement) classnode.getPsi()).getValue(); 35 | } 36 | return classexp; 37 | } 38 | 39 | @Nullable 40 | public JFlexElement getReturnType() { 41 | JFlexExpression classexp = null; 42 | ASTNode returnnode = getNode().findChildByType(JFlexElementTypes.TYPE_STATEMENT); 43 | if (returnnode != null) { 44 | classexp = ((JFlexTypeStatement) returnnode.getPsi()).getValue(); 45 | } 46 | return classexp; 47 | } 48 | 49 | public JFlexExpression[] getImplementedInterfaces() { 50 | JFlexExpression[] result = new JFlexExpression[0]; 51 | ASTNode implmentsnode = getNode().findChildByType(JFlexElementTypes.IMPLEMENTS_STATEMENT); 52 | if (implmentsnode != null) { 53 | result = ((JFlexImplementsStatement) implmentsnode.getPsi()).getInterfaces(); 54 | } 55 | return result; 56 | } 57 | 58 | public JFlexMacroDefinition[] getDeclaredMacroses() { 59 | ASTNode[] macroses = getNode().getChildren(MACROSET); 60 | JFlexMacroDefinition[] result = new JFlexMacroDefinition[macroses.length]; 61 | int i = 0; 62 | for (ASTNode node : macroses) { 63 | result[i++] = (JFlexMacroDefinition) node.getPsi(); 64 | } 65 | return result; 66 | } 67 | 68 | @Nullable 69 | public JFlexJavaCode getImports() { 70 | return getNode().getFirstChildNode().getElementType() == JFlexElementTypes.JAVA_CODE ? (JFlexJavaCode) getNode().getFirstChildNode().getPsi() : null; 71 | } 72 | 73 | public JFlexStateStatement[] getStateStatements() { 74 | ASTNode[] statestatements = getNode().getChildren(STATESTATEMENTSET); 75 | JFlexStateStatement[] result = new JFlexStateStatement[statestatements.length]; 76 | int i = 0; 77 | for (ASTNode node : statestatements) { 78 | result[i++] = (JFlexStateStatement) node.getPsi(); 79 | } 80 | return result; 81 | } 82 | 83 | @NotNull 84 | public FileType getFileType() { 85 | return JFlexFileType.FILE_TYPE; 86 | } 87 | 88 | public String toString() { 89 | return "JFlex: " + getName(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/parser/JFlexParserDefinition.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.parser; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.lang.LanguageUtil; 5 | import com.intellij.lang.ParserDefinition; 6 | import com.intellij.lang.PsiParser; 7 | import com.intellij.lexer.Lexer; 8 | import com.intellij.openapi.project.Project; 9 | import com.intellij.psi.FileViewProvider; 10 | import com.intellij.psi.PsiElement; 11 | import com.intellij.psi.PsiFile; 12 | import com.intellij.psi.tree.IElementType; 13 | import com.intellij.psi.tree.IFileElementType; 14 | import com.intellij.psi.tree.TokenSet; 15 | import org.intellij.lang.jflex.JFlexElementTypes; 16 | import org.intellij.lang.jflex.lexer.JFlexParsingLexer; 17 | import org.intellij.lang.jflex.parser.JFlexParser; 18 | import org.intellij.lang.jflex.psi.impl.*; 19 | import org.jetbrains.annotations.NotNull; 20 | 21 | /** 22 | * JFlex parser. 23 | * 24 | * @author Alexey Efimov 25 | */ 26 | public class JFlexParserDefinition implements ParserDefinition { 27 | @NotNull 28 | public Lexer createLexer(Project project) { 29 | return new JFlexParsingLexer(); 30 | } 31 | 32 | public PsiParser createParser(Project project) { 33 | return new JFlexParser(project); 34 | } 35 | 36 | public IFileElementType getFileNodeType() { 37 | return JFlexElementTypes.FILE; 38 | } 39 | 40 | @NotNull 41 | public TokenSet getWhitespaceTokens() { 42 | return JFlexElementTypes.WHITE_SPACES; 43 | } 44 | 45 | @NotNull 46 | public TokenSet getCommentTokens() { 47 | return JFlexElementTypes.COMMENTS; 48 | } 49 | 50 | @NotNull 51 | public PsiElement createElement(ASTNode node) { 52 | IElementType type = node.getElementType(); 53 | if (type == JFlexElementTypes.CLASS_STATEMENT) { 54 | return new JFlexClassStatementImpl(node); 55 | } else if (type == JFlexElementTypes.STATE_STATEMENT) { 56 | return new JFlexStateStatementImpl(node); 57 | } else if (type == JFlexElementTypes.STATE_DEFINITION) { 58 | return new JFlexStateDefinitionImpl(node); 59 | } else if (type == JFlexElementTypes.STATE_REF) { 60 | return new JFlexStateReferenceImpl(node); 61 | } else if (type == JFlexElementTypes.MACRO_DEFINITION) { 62 | return new JFlexMacroDefinitionImpl(node); 63 | } else if (type == JFlexElementTypes.IMPLEMENTS_STATEMENT) { 64 | return new JFlexImplementsStatementImpl(node); 65 | } else if (type == JFlexElementTypes.TYPE_STATEMENT) { 66 | return new JFlexTypeStatementImpl(node); 67 | } else if (type == JFlexElementTypes.JAVA_CODE) { 68 | return new JFlexJavaCodeImpl(node); 69 | } else if (type == JFlexElementTypes.REGEXP_MACROS_REF) { 70 | return new JFlexMacroReferenceImpl(node); 71 | } else if (type == JFlexElementTypes.SECTION) { 72 | return new JFlexSectionImpl(node); 73 | } else if (type == JFlexElementTypes.REGEXP) { 74 | return new JFlexRegexpImpl(node); 75 | } 76 | return new JFlexExpressionImpl(node); 77 | } 78 | 79 | public PsiFile createFile(FileViewProvider viewProvider) { 80 | return new JFlexPsiFileImpl(viewProvider); 81 | } 82 | 83 | public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode left, ASTNode right) { 84 | final Lexer lexer = createLexer(left.getPsi().getProject()); 85 | return LanguageUtil.canStickTokensTogetherByLexer(left, right, lexer); 86 | } 87 | 88 | @NotNull 89 | public TokenSet getStringLiteralElements() { 90 | return JFlexElementTypes.COMMENTS; 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /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/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/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/options/JFlexSettingsForm.form: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 |
    92 | -------------------------------------------------------------------------------- /src/main/java/org/intellij/lang/jflex/parser/JFlexParser.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.parser; 2 | 3 | import com.intellij.lang.ASTNode; 4 | import com.intellij.lang.PsiBuilder; 5 | import com.intellij.lang.PsiParser; 6 | import com.intellij.openapi.diagnostic.Logger; 7 | import com.intellij.openapi.project.Project; 8 | import com.intellij.psi.tree.IElementType; 9 | import org.intellij.lang.jflex.JFlexElementTypes; 10 | import org.intellij.lang.jflex.util.JFlexBundle; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | /** 14 | * Parser. 15 | * 16 | * @author Alexey Efimov, Max Ishchenko 17 | */ 18 | public class JFlexParser implements PsiParser { 19 | 20 | private static final Logger LOG = Logger.getInstance("#JFlexParser"); 21 | 22 | private final Project project; 23 | 24 | public JFlexParser(Project project) { 25 | this.project = project; 26 | } 27 | 28 | @NotNull 29 | public ASTNode parse(IElementType root, PsiBuilder builder) { 30 | 31 | final PsiBuilder.Marker rootMarker = builder.mark(); 32 | 33 | while (!builder.eof()) { 34 | parse(builder); 35 | } 36 | rootMarker.done(root); 37 | 38 | return builder.getTreeBuilt(); 39 | 40 | } 41 | 42 | private void parse(PsiBuilder builder) { 43 | IElementType first = builder.getTokenType(); 44 | if (first == JFlexElementTypes.MACROS) { 45 | parseMacroDefinition(builder); 46 | } else if (first == JFlexElementTypes.CLASS_KEYWORD) { 47 | parseClassStatement(builder); 48 | } else if (first == JFlexElementTypes.STATE_KEYWORD) { 49 | parseStateStatement(builder); 50 | } else if (first == JFlexElementTypes.XSTATE_KEYWORD) { 51 | parseXstateStatement(builder); 52 | } else if (first == JFlexElementTypes.STATE_REF) { 53 | parseStateReference(builder); 54 | } else if (first == JFlexElementTypes.IMPLEMENTS_KEYWORD) { 55 | parseImplementsStatement(builder); 56 | } else if (first == JFlexElementTypes.TYPE_KEYWORD) { 57 | parseTypeStatement(builder); 58 | } else if (first == JFlexElementTypes.JAVA_CODE) { 59 | parseJavaCode(builder); 60 | } else if (first == JFlexElementTypes.REGEXP_MACROS_REF) { 61 | parseMacroReference(builder); 62 | } else { 63 | builder.advanceLexer(); 64 | } 65 | } 66 | 67 | private void parseStateReference(PsiBuilder builder) { 68 | PsiBuilder.Marker mark = builder.mark(); 69 | builder.advanceLexer(); 70 | mark.done(JFlexElementTypes.STATE_REF); 71 | } 72 | 73 | private void parseCommaSeparatedOptionStatement(PsiBuilder builder, IElementType finishWith) { 74 | parseCommaSeparatedOptionStatement(builder, finishWith, JFlexElementTypes.OPTION_PARAMETER); 75 | } 76 | 77 | private void parseCommaSeparatedOptionStatement(PsiBuilder builder, IElementType finishWith, IElementType markWith) { 78 | 79 | PsiBuilder.Marker stateMarker = builder.mark(); 80 | builder.advanceLexer(); 81 | 82 | boolean first = true; 83 | 84 | while (builder.getTokenType() == JFlexElementTypes.OPTION_PARAMETER || builder.getTokenType() == JFlexElementTypes.OPTION_COMMA) { 85 | 86 | if (first) { 87 | first = false; 88 | } else { 89 | //parsing commas or go to next expr 90 | if (builder.getTokenType() == JFlexElementTypes.OPTION_COMMA) { 91 | builder.advanceLexer(); 92 | } else { 93 | builder.error(JFlexBundle.message("parser.comma.expected")); 94 | } 95 | } 96 | 97 | PsiBuilder.Marker interfaceMarker = builder.mark(); 98 | if (builder.getTokenType() == JFlexElementTypes.OPTION_PARAMETER) { 99 | builder.advanceLexer(); 100 | interfaceMarker.done(markWith); 101 | } else { 102 | builder.error(JFlexBundle.message("parser.expression.expected")); 103 | interfaceMarker.drop(); 104 | break; 105 | } 106 | } 107 | 108 | stateMarker.done(finishWith); 109 | 110 | } 111 | 112 | private void parseStateStatement(PsiBuilder builder) { 113 | parseCommaSeparatedOptionStatement(builder, JFlexElementTypes.STATE_STATEMENT, JFlexElementTypes.STATE_DEFINITION); 114 | 115 | } 116 | 117 | private void parseXstateStatement(PsiBuilder builder) { 118 | parseCommaSeparatedOptionStatement(builder, JFlexElementTypes.STATE_STATEMENT, JFlexElementTypes.STATE_DEFINITION); 119 | } 120 | 121 | private void parseMacroDefinition(PsiBuilder builder) { 122 | 123 | PsiBuilder.Marker macroDefinition = builder.mark(); 124 | builder.advanceLexer(); 125 | 126 | if (builder.getTokenType() != JFlexElementTypes.EQ) { 127 | builder.error(JFlexBundle.message("parser.eq.expected")); 128 | } else { 129 | builder.advanceLexer(); 130 | } 131 | 132 | int found = 0; 133 | PsiBuilder.Marker macrovalue = builder.mark(); 134 | 135 | while (JFlexElementTypes.REGEXP_SCOPE.contains(builder.getTokenType())) { 136 | found++; 137 | builder.advanceLexer(); 138 | } 139 | 140 | if (found == 0) { 141 | macrovalue.drop(); 142 | builder.error(JFlexBundle.message("parser.macrovalue.expected")); 143 | } else { 144 | macrovalue.done(JFlexElementTypes.REGEXP); 145 | } 146 | 147 | macroDefinition.done(JFlexElementTypes.MACRO_DEFINITION); 148 | 149 | } 150 | 151 | private void parseMacroReference(PsiBuilder builder) { 152 | PsiBuilder.Marker macroMarker = builder.mark(); 153 | builder.advanceLexer(); 154 | macroMarker.done(JFlexElementTypes.REGEXP_MACROS_REF); 155 | } 156 | 157 | private void parseImplementsStatement(PsiBuilder builder) { 158 | parseCommaSeparatedOptionStatement(builder, JFlexElementTypes.IMPLEMENTS_STATEMENT); 159 | } 160 | 161 | private void parseTypeStatement(PsiBuilder builder) { 162 | LOG.assertTrue(builder.getTokenType() == JFlexElementTypes.TYPE_KEYWORD); 163 | PsiBuilder.Marker marker = builder.mark(); 164 | builder.advanceLexer(); 165 | parseOptionParamExpression(builder); 166 | marker.done(JFlexElementTypes.TYPE_STATEMENT); 167 | } 168 | 169 | private void parseJavaCode(PsiBuilder builder) { 170 | PsiBuilder.Marker marker = builder.mark(); 171 | builder.advanceLexer(); 172 | marker.done(JFlexElementTypes.JAVA_CODE); 173 | } 174 | 175 | private void parseClassStatement(PsiBuilder builder) { 176 | LOG.assertTrue(builder.getTokenType() == JFlexElementTypes.CLASS_KEYWORD); 177 | PsiBuilder.Marker marker = builder.mark(); 178 | builder.advanceLexer(); 179 | parseOptionParamExpression(builder); 180 | marker.done(JFlexElementTypes.CLASS_STATEMENT); 181 | } 182 | 183 | private void parseOptionParamExpression(PsiBuilder builder) { 184 | PsiBuilder.Marker expr = builder.mark(); 185 | if (builder.getTokenType() != JFlexElementTypes.OPTION_PARAMETER) { 186 | builder.error(JFlexBundle.message("parser.expression.expected")); 187 | expr.drop(); 188 | } else { 189 | builder.advanceLexer(); 190 | expr.done(JFlexElementTypes.OPTION_PARAMETER); 191 | } 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/options/JFlexSettingsForm.java: -------------------------------------------------------------------------------- 1 | package org.intellij.lang.jflex.options; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | import java.util.Arrays; 6 | import java.util.List; 7 | import java.util.ResourceBundle; 8 | 9 | import com.intellij.openapi.components.PersistentStateComponent; 10 | import com.intellij.openapi.fileChooser.FileChooserDescriptor; 11 | import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; 12 | import com.intellij.openapi.ui.ComponentWithBrowseButton; 13 | import com.intellij.openapi.ui.FixedSizeButton; 14 | import com.intellij.openapi.ui.Messages; 15 | import com.intellij.openapi.ui.TextComponentAccessor; 16 | import com.intellij.openapi.util.text.StringUtil; 17 | import com.intellij.ui.IdeBorderFactory; 18 | import com.intellij.ui.StateRestoringCheckBox; 19 | import com.intellij.ui.TextFieldWithStoredHistory; 20 | import com.intellij.uiDesigner.core.GridConstraints; 21 | import com.intellij.uiDesigner.core.GridLayoutManager; 22 | import com.intellij.uiDesigner.core.Spacer; 23 | import org.intellij.lang.jflex.util.JFlexBundle; 24 | import org.jetbrains.annotations.NonNls; 25 | import org.jetbrains.annotations.NotNull; 26 | 27 | /** 28 | * JFlex options. 29 | * 30 | * @author Alexey Efimov 31 | */ 32 | public final class JFlexSettingsForm implements PersistentStateComponent { 33 | @NonNls 34 | private static final String JFLEX_ENABLED_COMPILATION_KEY = "JFlex.EnabledCompilation"; 35 | @NonNls 36 | private static final String JFLEX_HOME_KEY = "JFlex.Home"; 37 | @NonNls 38 | private static final String JFLEX_SKELETON_KEY = "JFlex.Skeleton"; 39 | @NonNls 40 | private static final String JFLEX_OPTIONS_KEY = "JFlex.Options"; 41 | @NonNls 42 | private static final String JFLEX_ENABLED_EMBED_JAVA_KEY = "JFlex.EnabledEmbedJava"; 43 | 44 | private ComponentWithBrowseButton jFlexHomeTextField; 45 | private ComponentWithBrowseButton skeletonPathTextField; 46 | private JPanel formComponent; 47 | private TextFieldWithStoredHistory commandLineOptionsTextField; 48 | private JCheckBox enabledEmbedJavaCheckBox; 49 | private JCheckBox enabledCompilationCheckBox; 50 | 51 | private final JFlexSettings settings = new JFlexSettings(); 52 | 53 | public JFlexSettingsForm(JFlexSettings settings) { 54 | $$$setupUI$$$(); 55 | FileChooserDescriptor folderDescriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); 56 | FileChooserDescriptor fileDescriptor = FileChooserDescriptorFactory.createSingleLocalFileDescriptor(); 57 | 58 | jFlexHomeTextField.addBrowseFolderListener(JFlexBundle.message("select.jflex.home"), JFlexBundle.message("please.select.jflex.folder"), null, folderDescriptor, new HistoryAccessor()); 59 | skeletonPathTextField.addBrowseFolderListener(JFlexBundle.message("select.skeleton.file"), JFlexBundle.message("please.select.jflex.skeleton.file"), null, fileDescriptor, new HistoryAccessor()); 60 | 61 | loadState(settings); 62 | } 63 | 64 | private void createUIComponents() { 65 | enabledCompilationCheckBox = new StateRestoringCheckBox(JFLEX_ENABLED_COMPILATION_KEY, true); 66 | TextFieldWithStoredHistory jflexHomeHistory = createHistoryTextField(JFLEX_HOME_KEY, JFlexSettings.getDefaultJFlexHome()); 67 | jFlexHomeTextField = new ComponentWithBrowseButton(jflexHomeHistory, null); 68 | fixButton(jflexHomeHistory, jFlexHomeTextField); 69 | TextFieldWithStoredHistory skeletonPathHistory = createHistoryTextField(JFLEX_SKELETON_KEY, JFlexSettings.getDefaultSkeletonPath(JFlexSettings.getDefaultJFlexHome())); 70 | skeletonPathTextField = new ComponentWithBrowseButton(skeletonPathHistory, null); 71 | fixButton(skeletonPathHistory, skeletonPathTextField); 72 | commandLineOptionsTextField = createHistoryTextField(JFLEX_OPTIONS_KEY, JFlexSettings.DEFAULT_OPTIONS_CHARAT_NOBAK); 73 | enabledEmbedJavaCheckBox = new StateRestoringCheckBox(JFLEX_ENABLED_EMBED_JAVA_KEY, true); 74 | } 75 | 76 | private void fixButton(final TextFieldWithStoredHistory historyField, ComponentWithBrowseButton control) { 77 | FixedSizeButton button = control.getButton(); 78 | control.remove(button); 79 | BorderLayout borderLayout = new BorderLayout(); 80 | JPanel buttonPanel = new JPanel(borderLayout); 81 | buttonPanel.setBorder(IdeBorderFactory.createEmptyBorder(4, 0, 4, 0)); 82 | buttonPanel.add(button, BorderLayout.CENTER); 83 | control.add(buttonPanel, BorderLayout.EAST); 84 | button.setAttachedComponent(new JComponent() { 85 | public Dimension getPreferredSize() { 86 | Dimension size = historyField.getTextEditor().getPreferredSize(); 87 | return new Dimension(-1, size.height + 6); 88 | } 89 | 90 | }); 91 | } 92 | 93 | @SuppressWarnings({"unchecked"}) 94 | private static TextFieldWithStoredHistory createHistoryTextField(@NotNull String name, @NotNull String... defaultValues) { 95 | TextFieldWithStoredHistory storedHistory = new TextFieldWithStoredHistoryBugFixed(name); 96 | storedHistory.reset(); 97 | List list = storedHistory.getHistory(); 98 | list.removeAll(Arrays.asList(defaultValues)); 99 | if (list.isEmpty()) { 100 | // Default histories 101 | for (String defaultValue : defaultValues) { 102 | setTextWithHistory(storedHistory, defaultValue); 103 | } 104 | } else { 105 | storedHistory.setSelectedItem(list.get(list.size() - 1)); 106 | } 107 | return storedHistory; 108 | } 109 | 110 | public JComponent getFormComponent() { 111 | return formComponent; 112 | } 113 | 114 | public boolean isModified(JFlexSettings state) { 115 | return enabledCompilationCheckBox.isSelected() != state.ENABLED_COMPILATION || 116 | !jFlexHomeTextField.getChildComponent().getText().equals(state.JFLEX_HOME) || 117 | !skeletonPathTextField.getChildComponent().getText().equals(state.SKELETON_PATH) || 118 | !commandLineOptionsTextField.getText().equals(state.COMMAND_LINE_OPTIONS) || 119 | enabledEmbedJavaCheckBox.isSelected() != state.ENABLED_EMBED_JAVA; 120 | } 121 | 122 | /** 123 | * Method generated by IntelliJ IDEA GUI Designer 124 | * >>> IMPORTANT!! <<< 125 | * DO NOT edit this method OR call it in your code! 126 | * 127 | * @noinspection ALL 128 | */ 129 | private void $$$setupUI$$$() { 130 | createUIComponents(); 131 | formComponent = new JPanel(); 132 | formComponent.setLayout(new GridLayoutManager(5, 2, new Insets(0, 0, 0, 0), -1, -1)); 133 | final JLabel label1 = new JLabel(); 134 | this.$$$loadLabelText$$$(label1, ResourceBundle.getBundle("org/intellij/lang/jflex/util/JFlexBundle").getString("path.to.jflex")); 135 | formComponent.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); 136 | final Spacer spacer1 = new Spacer(); 137 | formComponent.add(spacer1, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); 138 | formComponent.add(jFlexHomeTextField, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); 139 | final JLabel label2 = new JLabel(); 140 | this.$$$loadLabelText$$$(label2, ResourceBundle.getBundle("org/intellij/lang/jflex/util/JFlexBundle").getString("skeleton.file")); 141 | formComponent.add(label2, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); 142 | formComponent.add(skeletonPathTextField, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); 143 | final JLabel label3 = new JLabel(); 144 | this.$$$loadLabelText$$$(label3, ResourceBundle.getBundle("org/intellij/lang/jflex/util/JFlexBundle").getString("command.line.options")); 145 | formComponent.add(label3, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); 146 | formComponent.add(commandLineOptionsTextField, new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); 147 | this.$$$loadButtonText$$$(enabledEmbedJavaCheckBox, ResourceBundle.getBundle("org/intellij/lang/jflex/util/JFlexBundle").getString("enabled.embed.java.code.support")); 148 | formComponent.add(enabledEmbedJavaCheckBox, new GridConstraints(3, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); 149 | label1.setLabelFor(jFlexHomeTextField); 150 | label2.setLabelFor(skeletonPathTextField); 151 | label3.setLabelFor(commandLineOptionsTextField); 152 | } 153 | 154 | /** 155 | * @noinspection ALL 156 | */ 157 | private void $$$loadLabelText$$$(JLabel component, String text) { 158 | StringBuffer result = new StringBuffer(); 159 | boolean haveMnemonic = false; 160 | char mnemonic = '\0'; 161 | int mnemonicIndex = -1; 162 | for (int i = 0; i < text.length(); i++) { 163 | if (text.charAt(i) == '&') { 164 | i++; 165 | if (i == text.length()) { 166 | break; 167 | } 168 | if (!haveMnemonic && text.charAt(i) != '&') { 169 | haveMnemonic = true; 170 | mnemonic = text.charAt(i); 171 | mnemonicIndex = result.length(); 172 | } 173 | } 174 | result.append(text.charAt(i)); 175 | } 176 | component.setText(result.toString()); 177 | if (haveMnemonic) { 178 | component.setDisplayedMnemonic(mnemonic); 179 | component.setDisplayedMnemonicIndex(mnemonicIndex); 180 | } 181 | } 182 | 183 | /** 184 | * @noinspection ALL 185 | */ 186 | private void $$$loadButtonText$$$(AbstractButton component, String text) { 187 | StringBuffer result = new StringBuffer(); 188 | boolean haveMnemonic = false; 189 | char mnemonic = '\0'; 190 | int mnemonicIndex = -1; 191 | for (int i = 0; i < text.length(); i++) { 192 | if (text.charAt(i) == '&') { 193 | i++; 194 | if (i == text.length()) { 195 | break; 196 | } 197 | if (!haveMnemonic && text.charAt(i) != '&') { 198 | haveMnemonic = true; 199 | mnemonic = text.charAt(i); 200 | mnemonicIndex = result.length(); 201 | } 202 | } 203 | result.append(text.charAt(i)); 204 | } 205 | component.setText(result.toString()); 206 | if (haveMnemonic) { 207 | component.setMnemonic(mnemonic); 208 | component.setDisplayedMnemonicIndex(mnemonicIndex); 209 | } 210 | } 211 | 212 | /** 213 | * @noinspection ALL 214 | */ 215 | public JComponent $$$getRootComponent$$$() { 216 | return formComponent; 217 | } 218 | 219 | /** 220 | * Fixed text component. Enabling is valid now. 221 | */ 222 | private static final class TextFieldWithStoredHistoryBugFixed extends TextFieldWithStoredHistory { 223 | public TextFieldWithStoredHistoryBugFixed(String name) { 224 | super(name, false); 225 | } 226 | 227 | public void setEnabled(boolean enabled) { 228 | super.setEnabled(enabled); 229 | getTextEditor().setEnabled(enabled); 230 | getTextEditor().setEditable(enabled); 231 | } 232 | } 233 | 234 | private static class HistoryAccessor implements TextComponentAccessor { 235 | public String getText(TextFieldWithStoredHistory component) { 236 | return component.getText().replace('\\', '/'); 237 | } 238 | 239 | public void setText(TextFieldWithStoredHistory component, String text) { 240 | setTextWithHistory(component, text); 241 | } 242 | } 243 | 244 | public final JFlexSettings getState() { 245 | if (validate()) { 246 | settings.ENABLED_COMPILATION = enabledCompilationCheckBox.isSelected(); 247 | settings.JFLEX_HOME = jFlexHomeTextField.getChildComponent().getText(); 248 | settings.SKELETON_PATH = skeletonPathTextField.getChildComponent().getText(); 249 | settings.COMMAND_LINE_OPTIONS = commandLineOptionsTextField.getText(); 250 | settings.ENABLED_EMBED_JAVA = enabledEmbedJavaCheckBox.isSelected(); 251 | } 252 | return settings; 253 | } 254 | 255 | private boolean validate() { 256 | if (enabledCompilationCheckBox.isSelected()) { 257 | String text = jFlexHomeTextField.getChildComponent().getText(); 258 | if (StringUtil.isEmptyOrSpaces(text)) { 259 | Messages.showWarningDialog(jFlexHomeTextField, JFlexBundle.message("please.enter.path.to.jflex.home.directory"), JFlexBundle.message("jflex")); 260 | jFlexHomeTextField.requestFocus(); 261 | return false; 262 | } 263 | 264 | // All fine add to history 265 | jFlexHomeTextField.getChildComponent().addCurrentTextToHistory(); 266 | skeletonPathTextField.getChildComponent().addCurrentTextToHistory(); 267 | commandLineOptionsTextField.addCurrentTextToHistory(); 268 | } 269 | return true; 270 | } 271 | 272 | public final void loadState(JFlexSettings state) { 273 | settings.loadState(state); 274 | enabledCompilationCheckBox.setSelected(state.ENABLED_COMPILATION); 275 | setTextWithHistory(jFlexHomeTextField.getChildComponent(), state.JFLEX_HOME); 276 | setTextWithHistory(skeletonPathTextField.getChildComponent(), state.SKELETON_PATH); 277 | setTextWithHistory(commandLineOptionsTextField, state.COMMAND_LINE_OPTIONS); 278 | enabledEmbedJavaCheckBox.setSelected(state.ENABLED_EMBED_JAVA); 279 | } 280 | 281 | private static void setTextWithHistory(TextFieldWithStoredHistory component, String text) { 282 | if (StringUtil.isEmptyOrSpaces(text)) { 283 | component.setText(null); 284 | } else { 285 | component.setText(text); 286 | component.addCurrentTextToHistory(); 287 | } 288 | } 289 | 290 | } 291 | -------------------------------------------------------------------------------- /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 |