├── settings.gradle
├── demo.gif
├── src
├── main
│ ├── resources
│ │ ├── com
│ │ │ └── github
│ │ │ │ └── oowekyala
│ │ │ │ └── ijcc
│ │ │ │ ├── optionDescriptions
│ │ │ │ ├── JDK_VERSION.html
│ │ │ │ ├── jjtree
│ │ │ │ │ ├── NODE_PACKAGE.html
│ │ │ │ │ ├── BUILD_NODE_FILES.html
│ │ │ │ │ ├── MULTI.html
│ │ │ │ │ ├── NODE_DEFAULT_VOID.html
│ │ │ │ │ ├── NODE_PREFIX.html
│ │ │ │ │ ├── NODE_SCOPE_HOOK.html
│ │ │ │ │ ├── NODE_CLASS.html
│ │ │ │ │ ├── VISITOR.html
│ │ │ │ │ ├── VISITOR_EXCEPTION.html
│ │ │ │ │ ├── VISITOR_DATA_TYPE.html
│ │ │ │ │ ├── VISITOR_RETURN_TYPE.html
│ │ │ │ │ ├── NODE_EXTENDS.html
│ │ │ │ │ ├── JJTREE_OUTPUT_DIRECTORY.html
│ │ │ │ │ ├── NODE_USES_PARSER.html
│ │ │ │ │ ├── TRACK_TOKENS.html
│ │ │ │ │ └── NODE_FACTORY.html
│ │ │ │ ├── OUTPUT_DIRECTORY.html
│ │ │ │ ├── GRAMMAR_ENCODING.html
│ │ │ │ ├── ERROR_REPORTING.html
│ │ │ │ ├── SUPPORT_CLASS_VISIBILITY_PUBLIC.html
│ │ │ │ ├── BUILD_PARSER.html
│ │ │ │ ├── DEBUG_LOOKAHEAD.html
│ │ │ │ ├── TOKEN_EXTENDS.html
│ │ │ │ ├── UNICODE_INPUT.html
│ │ │ │ ├── TOKEN_FACTORY.html
│ │ │ │ ├── USER_TOKEN_MANAGER.html
│ │ │ │ ├── OTHER_AMBIGUITY_CHECK.html
│ │ │ │ ├── JAVA_TEMPLATE_TYPE.html
│ │ │ │ ├── BUILD_TOKEN_MANAGER.html
│ │ │ │ ├── IGNORE_CASE.html
│ │ │ │ ├── LOOKAHEAD.html
│ │ │ │ ├── TOKEN_MANAGER_USES_PARSER.html
│ │ │ │ ├── JAVA_UNICODE_ESCAPE.html
│ │ │ │ ├── DEBUG_PARSER.html
│ │ │ │ ├── CACHE_TOKENS.html
│ │ │ │ ├── DEBUG_TOKEN_MANAGER.html
│ │ │ │ ├── COMMON_TOKEN_ACTION.html
│ │ │ │ ├── USER_CHAR_STREAM.html
│ │ │ │ ├── SANITY_CHECK.html
│ │ │ │ ├── FORCE_LA_CHECK.html
│ │ │ │ ├── CHOICE_AMBIGUITY_CHECK.html
│ │ │ │ └── STATIC.html
│ │ │ │ ├── icons
│ │ │ │ ├── jccFile.svg
│ │ │ │ ├── jccFile_dark.svg
│ │ │ │ ├── jjtreeNode.svg
│ │ │ │ ├── tree.svg
│ │ │ │ ├── terminal.svg
│ │ │ │ ├── jccNavigateToGrammar.svg
│ │ │ │ ├── jccNavigateToGrammar_dark.svg
│ │ │ │ ├── jjtreeFile.svg
│ │ │ │ ├── jjtreeFile_dark.svg
│ │ │ │ ├── jjtreeNodeLocate.svg
│ │ │ │ ├── jjtreeNodeLocate_dark.svg
│ │ │ │ ├── jjtreeNode_alt.svg
│ │ │ │ ├── jccNavigateToNode.svg
│ │ │ │ ├── jccNavigateToNode_dark.svg
│ │ │ │ └── bnfProdAndNode.svg
│ │ │ │ ├── colorSchemes
│ │ │ │ ├── Darcula_Javacc.xml
│ │ │ │ └── Default_Javacc.xml
│ │ │ │ └── fileTemplates
│ │ │ │ └── JavaCC grammar.jj.ft
│ │ └── META-INF
│ │ │ ├── MANIFEST.mf
│ │ │ └── pluginIcon.svg
│ └── kotlin
│ │ └── com
│ │ └── github
│ │ └── oowekyala
│ │ └── ijcc
│ │ ├── util
│ │ ├── Constants.kt
│ │ ├── EnclosedLogger.kt
│ │ └── SoftReferenceCache.kt
│ │ ├── lang
│ │ ├── lexer
│ │ │ └── JavaccLexerAdapter.kt
│ │ ├── model
│ │ │ ├── AccessModifier.kt
│ │ │ ├── RegexKind.kt
│ │ │ ├── BaseCachedModelObject.kt
│ │ │ ├── JccVersion.kt
│ │ │ ├── J21Option.kt
│ │ │ ├── GrammarNature.kt
│ │ │ └── IGrammarOptions.kt
│ │ ├── psi
│ │ │ ├── IJccElementType.kt
│ │ │ ├── IJccTokenType.kt
│ │ │ ├── stubs
│ │ │ │ ├── StubExtensions.kt
│ │ │ │ ├── JccStubElementType.kt
│ │ │ │ ├── indices
│ │ │ │ │ ├── IdeStubService.kt
│ │ │ │ │ ├── JjtreeQNameStubIndex.kt
│ │ │ │ │ ├── JccParserQnameIndexer.kt
│ │ │ │ │ └── JccStubElementTypeHolder.kt
│ │ │ │ ├── DataStreamUtils.kt
│ │ │ │ └── StubIndexService.kt
│ │ │ ├── JccOptionBinding.kt
│ │ │ ├── DepthFirstVisitor.kt
│ │ │ ├── JccNonTerminalProduction.kt
│ │ │ ├── JccIdentifierOwner.kt
│ │ │ ├── JccNodeExtensions.kt
│ │ │ ├── JccPsiElement.kt
│ │ │ ├── JccScopedExpansionUnit.kt
│ │ │ ├── JccJjtreeNodeDescriptorExpr.kt
│ │ │ ├── impl
│ │ │ │ ├── GrammarOptionsService.kt
│ │ │ │ ├── JccRegexExpansionUnitImpl.kt
│ │ │ │ ├── JccOptionBindingImpl.kt
│ │ │ │ ├── JccRegexSpecImpl.kt
│ │ │ │ ├── JccIdentifierImpl.kt
│ │ │ │ ├── JjtNodeClassOwnerImpl.kt
│ │ │ │ └── JccScopedExpansionUnitImpl.kt
│ │ │ ├── RegexLikeDFVisitor.kt
│ │ │ ├── JccTypesExt.kt
│ │ │ ├── JccJavaBlock.kt
│ │ │ ├── JccJavaExpression.kt
│ │ │ ├── JccJavaCompilationUnit.kt
│ │ │ ├── JccJavaAssignmentLhs.kt
│ │ │ ├── LookaheadExtensions.kt
│ │ │ ├── JccIdentifier.kt
│ │ │ ├── manipulators
│ │ │ │ ├── JccIdentifierManipulator.kt
│ │ │ │ ├── JccLiteralRegexManipulator.kt
│ │ │ │ ├── JccCommenter.kt
│ │ │ │ └── JccJavaCompilationUnitManipulator.kt
│ │ │ ├── PrettyPrintingExtensions.kt
│ │ │ ├── JccJavaNonTerminalProductionHeader.kt
│ │ │ ├── JavaccAstFactory.kt
│ │ │ ├── TraversalUtil.kt
│ │ │ ├── JjtNodeClassOwner.kt
│ │ │ └── JccJjtreeNodeDescriptor.kt
│ │ ├── injection
│ │ │ ├── InjectionUtil.kt
│ │ │ └── MultilineTextEscaper.kt
│ │ └── cfa
│ │ │ └── LastExpansion.kt
│ │ ├── ide
│ │ ├── refs
│ │ │ ├── PsiEltResolveResult.kt
│ │ │ ├── JccLexicalStateReference.kt
│ │ │ ├── JccRefVariantService.kt
│ │ │ ├── JccNonTerminalReference.kt
│ │ │ ├── JjtNodePolyReference.kt
│ │ │ └── JccBnfStringLiteralReference.kt
│ │ ├── intentions
│ │ │ ├── JccIntentionBase.kt
│ │ │ ├── ReplaceOptionValueIntention.kt
│ │ │ ├── RemoveNameFromRegexIntention.kt
│ │ │ ├── DeleteExpansionIntention.kt
│ │ │ ├── JccSelfTargetingEditorIntentionBase.kt
│ │ │ ├── CheckRegexIntention.kt
│ │ │ └── ReplaceSupersedingUsageWithReferenceIntentionFix.kt
│ │ ├── highlight
│ │ │ ├── JavaccSyntaxHighlighterFactory.kt
│ │ │ ├── JavaccSyntaxHighlighter.kt
│ │ │ └── InjectedJavaHighlightVisitor.kt
│ │ ├── findusages
│ │ │ ├── JccTextSelectioner.kt
│ │ │ ├── JccDescriptionProvider.kt
│ │ │ ├── JjtreeNodeReferenceSearcher.kt
│ │ │ ├── JccUsageTypeProvider.kt
│ │ │ ├── JccStringTokenFindUsagesHandlerFactory.kt
│ │ │ └── StringReferenceSearcher.kt
│ │ ├── completion
│ │ │ ├── LookupUtil.kt
│ │ │ ├── MultiCharTailType.kt
│ │ │ └── JccPatterns.kt
│ │ ├── gutter
│ │ │ ├── BaseTargetingLineMarkerProvider.kt
│ │ │ ├── JccProductionToParserLineMarkerProvider.kt
│ │ │ ├── JjtreeNodeClassLineMarkerProvider.kt
│ │ │ ├── JjtreePartialDeclarationLineMarkerProvider.kt
│ │ │ └── JjtNodeToGrammarLineMarkerProvider.kt
│ │ ├── rename
│ │ │ └── JccNamesValidator.kt
│ │ ├── structureview
│ │ │ └── JavaccStructureViewBuilderFactory.kt
│ │ ├── quickdoc
│ │ │ ├── JjtNodeDocMaker.kt
│ │ │ ├── JccOptionDocMaker.kt
│ │ │ └── JccLexicalStateDocMaker.kt
│ │ ├── inspections
│ │ │ ├── JccInspectionsProvider.kt
│ │ │ ├── JccInspectionBase.kt
│ │ │ ├── ActionWithinLookaheadInspection.kt
│ │ │ └── EmptyParserActionsInspection.kt
│ │ └── folding
│ │ │ └── JccFoldingOptionsProvider.kt
│ │ ├── icons
│ │ └── JccCoreIcons.kt
│ │ ├── settings
│ │ ├── JavaccProjectSettingsServiceImpl.kt
│ │ ├── JavaccProjectSettingsConfigurable.kt
│ │ ├── InjectionSupportLevel.kt
│ │ └── JavaccAppSettingsService.kt
│ │ ├── JavaccLanguage.kt
│ │ ├── JavaccFileType.kt
│ │ └── JavaccPairedBraceMatcher.kt
└── test
│ ├── resources
│ └── com
│ │ └── github
│ │ └── oowekyala
│ │ └── ijcc
│ │ └── lang
│ │ ├── parser
│ │ └── fixtures
│ │ │ ├── 21
│ │ │ └── Simple.ccc
│ │ │ ├── ExpansionFails.jjt
│ │ │ ├── RegexPrecedence.jjt
│ │ │ ├── Assignments.jjt
│ │ │ ├── Annotations.jjt
│ │ │ ├── JjtreeStuff.jjt
│ │ │ ├── TokenFail.jjt
│ │ │ ├── JavaTypes.jjt
│ │ │ ├── Lookaheads.jjt
│ │ │ ├── Parentheses.jjt
│ │ │ └── Tokens.jjt
│ │ ├── options
│ │ └── fixtures
│ │ │ ├── LookaheadOverride.jjt
│ │ │ ├── PackageOverride.jjt
│ │ │ └── InvalidOptionType.jjt
│ │ ├── injection
│ │ └── fixtures
│ │ │ └── CommonTreeBuilderTest.jjt
│ │ └── folding
│ │ └── fixtures
│ │ └── ParserActions.jjt
│ └── kotlin
│ └── com
│ └── github
│ └── oowekyala
│ └── ijcc
│ ├── ide
│ ├── inspections
│ │ ├── JccInspectionTestBase.kt
│ │ ├── ActionsWithinLookaheadInspectionTest.kt
│ │ ├── UnnamedRegexInspectionTest.kt
│ │ ├── UnnecessaryParenthesesInspectionTest.kt
│ │ ├── EmptyParserActionsInspectionTest.kt
│ │ ├── ConsecutiveParserActionsInspectionTest.kt
│ │ ├── JccInspectionSuppressorTest.kt
│ │ ├── LoopInRegexInspectionTest.kt
│ │ ├── RegexMayMatchEmptyStringInspectionTest.kt
│ │ ├── UnnecessaryAngledBracesRegexInspectionTest.kt
│ │ └── UnusedProductionInspectionTest.kt
│ ├── highlight
│ │ └── JccRichHighlightTest.kt
│ └── refs
│ │ └── ReferenceTest.kt
│ └── lang
│ ├── parser
│ ├── Jcc21ParserTests.kt
│ └── JccParserTests.kt
│ ├── JccFoldingBuilderTest.kt
│ ├── ParserTestDsl.kt
│ ├── JccNodeExtensionsTest.kt
│ ├── TestUtil.kt
│ ├── psi
│ ├── JccElementFactoryTest.kt
│ └── stubs
│ │ └── JccStubTest.kt
│ └── util
│ └── TestExtensions.kt
├── changelog.html
├── sandbox
└── README.md
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── justfile
├── make_icons
├── .idea
├── codeStyles
│ ├── codeStyleConfig.xml
│ └── Project.xml
├── vcs.xml
├── compiler.xml
├── kotlinc.xml
├── .gitignore
├── misc.xml
├── checkstyle-idea.xml
└── runConfigurations
│ └── Run_plugin_in_sandbox.xml
├── gradle.properties
├── LICENSE
├── .github
└── workflows
│ └── build.yml
└── do-release.sh
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'intellij-javacc'
2 |
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oowekyala/intellij-javacc/HEAD/demo.gif
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/JDK_VERSION.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/changelog.html:
--------------------------------------------------------------------------------
1 |
What's fixed:
2 |
3 | Fix #35: exception when loading plugin
4 |
5 |
--------------------------------------------------------------------------------
/sandbox/README.md:
--------------------------------------------------------------------------------
1 | Launch the plugin in a sandbox IDE, in this directory:
2 | ```
3 | ./gradlew runIde
4 | ```
5 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oowekyala/intellij-javacc/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/justfile:
--------------------------------------------------------------------------------
1 |
2 | # Requires Java 11
3 |
4 | build:
5 | ./gradlew b
6 |
7 | alias b := build
8 |
9 | buildPlugin:
10 | ./gradlew buildPlugin
11 |
12 |
13 |
--------------------------------------------------------------------------------
/make_icons:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | svgo -f "src/main/resources/com/github/oowekyala/ijcc/icons" \
4 | -o "build/resources/main/com/github/oowekyala/ijcc/icons"
5 |
6 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/jjtree/NODE_PACKAGE.html:
--------------------------------------------------------------------------------
1 | The package to generate the node classes into. The default for this is the parser package.
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/jjtree/BUILD_NODE_FILES.html:
--------------------------------------------------------------------------------
1 | Generate sample implementations for SimpleNode and any other nodes used in the grammar.
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/jjtree/MULTI.html:
--------------------------------------------------------------------------------
1 | Generate a multi mode parse tree. The default for this is false, generating a simple mode parse tree.
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/jjtree/NODE_DEFAULT_VOID.html:
--------------------------------------------------------------------------------
1 | Instead of making each non-decorated production an indefinite node, make it void instead.
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/jjtree/NODE_PREFIX.html:
--------------------------------------------------------------------------------
1 | The prefix used to construct node class names from node identifiers
2 | in multi mode. The default for this is "AST".
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/jjtree/NODE_SCOPE_HOOK.html:
--------------------------------------------------------------------------------
1 | Insert calls to user-defined parser methods on entry and exit
2 | of every node scope. See Node Scope Hooks above.
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/OUTPUT_DIRECTORY.html:
--------------------------------------------------------------------------------
1 | This is a string valued option whose default value is the current
2 | directory. This controls where output files are generated.
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Datasource local storage ignored files
5 | /dataSources/
6 | /dataSources.local.xml
7 | # Editor-based HTTP Client requests
8 | /httpRequests/
9 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/jjtree/NODE_CLASS.html:
--------------------------------------------------------------------------------
1 | If set defines the name of a user-supplied class that will extend SimpleNode.
2 | Any tree nodes created will then be subclasses of NODE_CLASS.
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/icons/jccFile.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/icons/jccFile_dark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/jjtree/VISITOR.html:
--------------------------------------------------------------------------------
1 | Insert a jjtAccept() method in the node classes, and generate
2 | a visitor implementation with an entry for every node type used
3 | in the grammar.
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/util/Constants.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.util
2 |
3 | /**
4 | * Path to the root resource dir of the app, with no trailing slash.
5 | */
6 | const val ResourcePrefix = "/com/github/oowekyala/ijcc"
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/GRAMMAR_ENCODING.html:
--------------------------------------------------------------------------------
1 | Return the file encoding (e.g., UTF-8, ISO_8859-1, MacRoman); this will return the
2 | file.encoding system property if no value was explicitly set
3 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/jjtree/VISITOR_EXCEPTION.html:
--------------------------------------------------------------------------------
1 | If this option is set, it is used in the throws clause of the
2 | generated jjtAccept() methods and the visit() methods.
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/colorSchemes/Darcula_Javacc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/colorSchemes/Default_Javacc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlin.code.style=official
2 | org.gradle.jvmargs=-Xmx2G
3 | #https://plugins.jetbrains.com/docs/intellij/using-kotlin.html#incremental-compilation
4 | kotlin.incremental.useClasspathSnapshot=false
5 | kotlin.stdlib.default.dependency = false
6 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/ERROR_REPORTING.html:
--------------------------------------------------------------------------------
1 | Setting this option to false causes errors due to parse errors to be reported
2 | in somewhat less detail. The only reason to set this option to
3 | false is to improve performance.
4 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/jjtree/VISITOR_DATA_TYPE.html:
--------------------------------------------------------------------------------
1 | If this option is set, it is used in the signature of the generated
2 | jjtAccept() methods and the visit() methods
3 | as the type of the data argument.
4 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/jjtree/VISITOR_RETURN_TYPE.html:
--------------------------------------------------------------------------------
1 | If this option is set, it is used in the signature of the generated
2 | jjtAccept() methods and the visit() methods
3 | as the return type of the method.
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/lexer/JavaccLexerAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.lexer
2 |
3 | import com.intellij.lexer.FlexAdapter
4 | class JavaccLexerAdapter @JvmOverloads constructor(isCCC: Boolean = false) : FlexAdapter(JavaccLexer(isCCC))
5 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/model/AccessModifier.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.model
2 |
3 | /**
4 | * @author Clément Fournier
5 | */
6 | enum class AccessModifier {
7 | PRIVATE,
8 | PACKAGE_LOCAL,
9 | PROTECTED,
10 | PUBLIC
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/icons/jjtreeNode.svg:
--------------------------------------------------------------------------------
1 | n
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/jjtree/NODE_EXTENDS.html:
--------------------------------------------------------------------------------
1 | The superclass for the SimpleNode class. By providing a custom
2 | superclass you may be able to avoid the need to edit the generated
3 | SimpleNode.java. See the examples/Interpreter for an example
4 | usage.
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/SUPPORT_CLASS_VISIBILITY_PUBLIC.html:
--------------------------------------------------------------------------------
1 | The default action is to generate support classes (such as Token.java, ParseException.java
2 | etc) with public visibility. If set to false, the classes will
3 | be generated with package-private visibility.
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/jjtree/JJTREE_OUTPUT_DIRECTORY.html:
--------------------------------------------------------------------------------
1 | By default, JJTree generates its output in the directory specified
2 | in the global {option_link OUTPUT_DIRECTORY} setting. Explicitly setting this
3 | option allows the user to separate the parser from the tree
4 | files.
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/BUILD_PARSER.html:
--------------------------------------------------------------------------------
1 | By default JavaCC generates a Java parser file. When set to false,
2 | the parser file is not generated.
3 | Typically, this option is set to false when you wish to generate
4 | only the token manager and use it without the associated parser.
5 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/jjtree/NODE_USES_PARSER.html:
--------------------------------------------------------------------------------
1 | JJTree will use an alternate form of the node construction routines
2 | where it passes the parser object in. For example,
3 |
4 | public static Node MyNode.jjtCreate(MyParser p, int id);
5 |
6 | MyNode(MyParser p, int id);
7 |
8 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/MANIFEST.mf:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Class-Path: light-psi-all.jar lib/annotations.jar lib/asm-all-7.0.1.ja
3 | r lib/automaton-1.12-1.jar lib/extensions.jar lib/guava-25.1-jre.jar
4 | lib/idea.jar lib/jdom.jar lib/picocontainer-1.2.jar lib/platform-api.
5 | jar lib/platform-impl.jar lib/trove4j.jar lib/util.jar
6 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/DEBUG_LOOKAHEAD.html:
--------------------------------------------------------------------------------
1 | Setting this option to true causes the parser to generate all the tracing
2 | information it does when the option {option_link DEBUG_PARSER}
3 | is true, and in addition, also causes it to generated a trace of actions performed
4 | during lookahead operation.
5 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/TOKEN_EXTENDS.html:
--------------------------------------------------------------------------------
1 | This is a string option whose default value is "", meaning that
2 | the generated Token class will extend java.lang.Object. This
3 | option may be set to the name of a class that will be used as
4 | the base class for the generated Token class.
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/UNICODE_INPUT.html:
--------------------------------------------------------------------------------
1 | When set to true, the generated parser uses uses an input stream object
2 | that reads Unicode files. By default, ASCII files are assumed.
3 |
4 | This option is ignored if either of options {option_link USER_TOKEN_MANAGER},
5 | {option_link USER_CHAR_STREAM} is set to true.
6 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/TOKEN_FACTORY.html:
--------------------------------------------------------------------------------
1 | This is a string option whose default value is "", meaning that
2 | Tokens will be created by calling Token.newToken(). If set the
3 | option names a Token factory class containing a public static
4 | Token newToken(int ofKind, String image) method.
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/IJccElementType.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.github.oowekyala.ijcc.JavaccLanguage
4 | import com.intellij.psi.tree.IElementType
5 |
6 | /**
7 | * @author Clément Fournier
8 | * @since 1.0
9 | */
10 | class IJccElementType(id: String) : IElementType(id, JavaccLanguage.INSTANCE)
11 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/IJccTokenType.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.github.oowekyala.ijcc.JavaccLanguage
4 | import com.intellij.psi.tree.IElementType
5 |
6 | /**
7 | * @author Clément Fournier
8 | * @since 1.0
9 | */
10 | class IJccTokenType(val id: String) : IElementType(id, JavaccLanguage.INSTANCE)
11 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/USER_TOKEN_MANAGER.html:
--------------------------------------------------------------------------------
1 | By default JavaCC generates a token manager that works on the specified grammar tokens.
2 | If this option is set to true, then the parser is generated to accept tokens from any
3 | token manager of type "TokenManager" - that interface is generated into the generated
4 | parser directory.
5 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/OTHER_AMBIGUITY_CHECK.html:
--------------------------------------------------------------------------------
1 | This is the number of tokens considered in checking all other kinds of choices
2 | (i.e., of the forms (A)*, (A)+, and (A)?) for ambiguity.
3 | This takes more time to do than the choice checking, and hence
4 | the default value is set to 1 rather than 2.
5 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/jjtree/TRACK_TOKENS.html:
--------------------------------------------------------------------------------
1 | Insert jjtGetFirstToken(), jjtSetFirstToken(), getLastToken(),
2 | and jjtSetLastToken() methods in SimpleNode. The FirstToken
3 | is automatically set up on entry to a node scope; the LastToken
4 | is automatically set up on exit from a node scope.
--------------------------------------------------------------------------------
/src/test/resources/com/github/oowekyala/ijcc/lang/parser/fixtures/ExpansionFails.jjt:
--------------------------------------------------------------------------------
1 | PARSER_BEGIN(JJTreeParser)
2 |
3 | package org.javacc.jjtree;
4 | /**
5 | * This is my parser declaration
6 | */
7 | public class JJTreeParser {
8 |
9 | }
10 |
11 | PARSER_END(JJTreeParser)
12 |
13 |
14 |
15 | void emptyAlt(): {}
16 | {
17 | a() | b() | | c()
18 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/model/RegexKind.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.model
2 |
3 | import java.util.*
4 |
5 | enum class RegexKind {
6 | TOKEN, SKIP, SPECIAL_TOKEN, MORE;
7 |
8 | companion object {
9 | val All: Set = EnumSet.allOf(RegexKind::class.java)
10 | val JustToken: Set = EnumSet.of(TOKEN)
11 | }
12 | }
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/JAVA_TEMPLATE_TYPE.html:
--------------------------------------------------------------------------------
1 | Style of java code generation.
2 |
3 | "classic" (default): Tightly coupled to Java IO classes - not GWT compatible.
4 | "modern" : GWT Compliant Output -- no external dependencies on GWT,
5 | but generated code adds loose coupling to IO
6 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/icons/tree.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/BUILD_TOKEN_MANAGER.html:
--------------------------------------------------------------------------------
1 | By default JavaCC generates a token manager class. When set to
2 | false the token manager file is not generated.
3 |
4 | The only reason to set this option to false is to save some time during parser generation when you fix problems
5 | in the parser part of the grammar file and leave the lexical
6 | specifications untouched.
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/IGNORE_CASE.html:
--------------------------------------------------------------------------------
1 | Setting this option to true causes the generated token manager to ignore
2 | case in the token specifications and the input files. This is
3 | useful for writing grammars for languages such as HTML. It is
4 | also possible to localize the effect of IGNORE_CASE by adding
5 | the [IGNORE_CASE] annotation on regex productions.
6 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/LOOKAHEAD.html:
--------------------------------------------------------------------------------
1 | The number of tokens to look ahead before making a decision
2 | at a choice point during parsing.
3 |
The smaller this number, the faster the parser. This number
4 | may be overridden for specific productions within the grammar
5 | as described later. See the description of the lookahead algorithm
6 | for complete details on how lookahead works.
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/refs/PsiEltResolveResult.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.refs
2 |
3 | import com.intellij.psi.PsiElement
4 | import com.intellij.psi.ResolveResult
5 |
6 | data class PsiEltResolveResult(private val myElt: T) :
7 | ResolveResult {
8 | override fun getElement(): T = myElt
9 |
10 | override fun isValidResult(): Boolean = true
11 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/stubs/StubExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi.stubs
2 |
3 | import com.intellij.psi.stubs.StubElement
4 |
5 | /**
6 | * @author Clément Fournier
7 | * @since 1.2
8 | */
9 |
10 |
11 | fun StubElement<*>.ancestors(includeSelf: Boolean): Sequence> =
12 | generateSequence(if (includeSelf) this else parentStub) { it.parentStub }
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/TOKEN_MANAGER_USES_PARSER.html:
--------------------------------------------------------------------------------
1 | When set to true, the generated token manager will include a field called
2 | parser that references the instantiating parser instance. The
3 | main reason for having a parser in a token manager is using some of its
4 | logic in lexical actions. This option has no effect if the {option_link STATIC} option is set
5 | to true.
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/fileTemplates/JavaCC grammar.jj.ft:
--------------------------------------------------------------------------------
1 | /*
2 | * Grammar for the ${NAME} language.
3 | *
4 | * Author: ${USER}
5 | * Date: ${YEAR}-${MONTH}-${DAY}
6 | *
7 | */
8 |
9 | options {
10 | // option=value
11 | }
12 |
13 | PARSER_BEGIN(${NAME})
14 |
15 | class ${NAME}Parser {
16 |
17 |
18 | }
19 |
20 | PARSER_END(${NAME})
21 |
22 | void root():
23 | {}
24 | {
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/JAVA_UNICODE_ESCAPE.html:
--------------------------------------------------------------------------------
1 | When set to true, the generated parser uses an input stream object that
2 | processes Java Unicode escapes (\u...) before sending characters
3 | to the token manager. By default, Java Unicode escapes are not
4 | processed.
5 |
6 | This option is ignored if either of options {option_link USER_TOKEN_MANAGER},
7 | {option_link USER_CHAR_STREAM} is set to true.
8 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/JccOptionBinding.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | interface JccOptionBinding : JccIdentifierOwner {
4 |
5 | val optionValue: JccOptionValue?
6 |
7 | override fun getName(): String
8 |
9 | /**
10 | * Nullable because it could be e.g. a LOOKAHEAD token.
11 | * Use [getName] directly.
12 | */
13 | override fun getNameIdentifier(): JccIdentifier?
14 |
15 | }
--------------------------------------------------------------------------------
/src/test/resources/com/github/oowekyala/ijcc/lang/parser/fixtures/RegexPrecedence.jjt:
--------------------------------------------------------------------------------
1 | PARSER_BEGIN(JJTreeParser)
2 |
3 | package org.javacc.jjtree;
4 | /**
5 | * This is my parser declaration
6 | */
7 | public class JJTreeParser {
8 |
9 | }
10 |
11 | PARSER_END(JJTreeParser)
12 |
13 |
14 |
15 | void named(): {}
16 | {
17 | < foo:
18 | }
19 |
20 | void ref(): {}
21 | {
22 | < foo
23 | }
24 | void inline(): {}
25 | {
26 | <
27 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/DepthFirstVisitor.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.intellij.psi.PsiElement
4 | import com.intellij.psi.PsiRecursiveVisitor
5 |
6 | /**
7 | * @author Clément Fournier
8 | * @since 1.0
9 | */
10 | open class DepthFirstVisitor : JccVisitor(), PsiRecursiveVisitor {
11 |
12 | override fun visitElement(element: PsiElement) {
13 | element.acceptChildren(this)
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/DEBUG_PARSER.html:
--------------------------------------------------------------------------------
1 | This option is used to obtain debugging information from the generated parser.
2 | Setting this option to true causes the parser to generate a trace
3 | of its actions. Tracing may be disabled by calling the method
4 | disable_tracing() in the generated parser class. Tracing may
5 | be subsequently enabled by calling the method enable_tracing()
6 | in the generated parser class.
7 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/icons/terminal.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/CACHE_TOKENS.html:
--------------------------------------------------------------------------------
1 | Setting this option to true causes the generated parser to lookahead
2 | for extra tokens ahead of time. This facilitates some performance
3 | improvements. However, in this case (when the option is true),
4 | interactive applications may not work since the parser needs
5 | to work synchronously with the availability of tokens from the
6 | input stream. In such cases, it's best to leave this option at
7 | its default value.
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/intentions/JccIntentionBase.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.intentions
2 |
3 | import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction
4 |
5 | /**
6 | * @author Clément Fournier
7 | * @since 1.0
8 | */
9 | abstract class JccIntentionBase(val name: String) : PsiElementBaseIntentionAction() {
10 |
11 | override fun getFamilyName(): String = name
12 |
13 | override fun getText(): String = name
14 |
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/src/test/resources/com/github/oowekyala/ijcc/lang/options/fixtures/LookaheadOverride.jjt:
--------------------------------------------------------------------------------
1 | options {
2 | LOOKAHEAD = 4;
3 | MULTI = true;
4 | }
5 |
6 | PARSER_BEGIN(JJTreeParser)
7 |
8 | package org.javacc.jjtree;
9 | /**
10 | * This is my parser declaration
11 | */
12 | public class JJTreeParser {
13 |
14 | void jjtreeOpenNodeScope(Node n) {
15 | ((JJTreeNode)n).setFirstToken(getToken(1));
16 | }
17 |
18 | }
19 |
20 | PARSER_END(JJTreeParser)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/DEBUG_TOKEN_MANAGER.html:
--------------------------------------------------------------------------------
1 | This option is used to obtain debugging information from the
2 | generated token manager. Setting this option to true causes the
3 | token manager to generate a trace of its actions. This trace is rather large
4 | and should only be used when you have a lexical error that has
5 | been reported to you and you cannot understand why. Typically,
6 | in this situation, you can determine the problem by looking at
7 | the last few lines of this trace.
8 |
--------------------------------------------------------------------------------
/src/test/resources/com/github/oowekyala/ijcc/lang/parser/fixtures/Assignments.jjt:
--------------------------------------------------------------------------------
1 | PARSER_BEGIN(JJTreeParser)
2 |
3 | package org.javacc.jjtree;
4 | /**
5 | * This is my parser declaration
6 | */
7 | public class JJTreeParser {
8 |
9 | }
10 |
11 | PARSER_END(JJTreeParser)
12 |
13 |
14 |
15 | void assignments(): {}
16 | {
17 | a=[
18 | a="h"
19 | a=< f: "olol">
20 | c=foo()
21 | // invalid parses
22 | a=("f")
23 | a=[h()]
24 | a=try {foo()}catch(Foo f){}
25 | }
--------------------------------------------------------------------------------
/src/main/resources/META-INF/pluginIcon.svg:
--------------------------------------------------------------------------------
1 | ]
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/test/resources/com/github/oowekyala/ijcc/lang/parser/fixtures/Annotations.jjt:
--------------------------------------------------------------------------------
1 | PARSER_BEGIN(JJTreeParser)
2 | public class JJTreeParser { }
3 | PARSER_END(JJTreeParser)
4 |
5 | // note: for now annotations on productions is not supported by our parser,
6 | // not sure if the javacc syntax allows that
7 |
8 | void p1(@Nullable T foo, List<@Nullable T> list): {} { "a" }
9 | void p2(T foo, @A List<@Nullable T> list): {} { "a" }
10 | void p2(T foo, @A List super @Nullable T> list): {} { "a" }
11 | @O int p2(): {} { "a" }
12 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/icons/jccNavigateToGrammar.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/icons/jccNavigateToGrammar_dark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/test/resources/com/github/oowekyala/ijcc/lang/options/fixtures/PackageOverride.jjt:
--------------------------------------------------------------------------------
1 | options {
2 | LOOKAHEAD = 4;
3 | NODE_PACKAGE = "org.foo";
4 | MULTI = true;
5 | }
6 |
7 | PARSER_BEGIN(JJTreeParser)
8 |
9 | package org.javacc.jjtree;
10 | /**
11 | * This is my parser declaration
12 | */
13 | public class JJTreeParser {
14 |
15 | void jjtreeOpenNodeScope(Node n) {
16 | ((JJTreeNode)n).setFirstToken(getToken(1));
17 | }
18 |
19 | }
20 |
21 | PARSER_END(JJTreeParser)
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/test/resources/com/github/oowekyala/ijcc/lang/options/fixtures/InvalidOptionType.jjt:
--------------------------------------------------------------------------------
1 | options {
2 | LOOKAHEAD = "60";
3 | NODE_DEFAULT_VOID = "true";
4 | NODE_PACKAGE = 6;
5 | }
6 |
7 | PARSER_BEGIN(JJTreeParser)
8 |
9 | package org.javacc.jjtree;
10 | /**
11 | * This is my parser declaration
12 | */
13 | public class JJTreeParser {
14 |
15 | void jjtreeOpenNodeScope(Node n) {
16 | ((JJTreeNode)n).setFirstToken(getToken(1));
17 | }
18 |
19 | }
20 |
21 | PARSER_END(JJTreeParser)
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/test/resources/com/github/oowekyala/ijcc/lang/parser/fixtures/21/Simple.ccc:
--------------------------------------------------------------------------------
1 |
2 | INJECT(Foo): {} {}
3 | INJECT(class Foo): {} {}
4 | INJECT(interface Foo): {} {}
5 |
6 | INJECT(Foo) {} {}
7 | INJECT(class Foo) {} {}
8 | INJECT(interface Foo) {} {}
9 |
10 | INCLUDE(Java)
11 | INCLUDE(Java) :{}
12 | INCLUDE("Java")
13 | INCLUDE("Java") :{}
14 | INCLUDE("Java"
15 | INCLUDE(
16 | INCLUDE
17 |
18 | // errors
19 | INJECT(interface Foo) {}
20 | INJECT(interface Foo):
21 |
22 | INJECT:{}
23 | INJECT {}
24 |
25 |
26 | void assignments(): {}
27 | {
28 | "&&"
29 | }
30 |
--------------------------------------------------------------------------------
/src/test/resources/com/github/oowekyala/ijcc/lang/injection/fixtures/CommonTreeBuilderTest.jjt:
--------------------------------------------------------------------------------
1 | PARSER_BEGIN(JJTreeParser)
2 |
3 | PARSER_END(JJTreeParser)
4 |
5 |
6 |
7 | void test1() #OptionBinding :
8 | {}
9 | {
10 | "ff" {jjtThis.foo();}
11 | }
12 |
13 | void test2() #OptionBinding :
14 | {}
15 | {
16 | "ff" "cd"
17 | }
18 |
19 | void test2() #OptionBinding :
20 | {}
21 | {
22 | "ff" {jjtThis.foo();} | "cd" {jjtThis.bar();}
23 | }
24 |
25 | void test2() #OptionBinding :
26 | {}
27 | {
28 | LOOKAHEAD({ jjtThis.bar() })
29 | "ff" | "cd" | "f" "c"
30 | }
31 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/ide/inspections/JccInspectionTestBase.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.inspections
2 |
3 | import com.github.oowekyala.ijcc.util.JccAnnotationTestBase
4 | import com.intellij.psi.PsiFile
5 |
6 | abstract class JccInspectionTestBase(
7 | private val inspection: JccInspectionBase
8 | ) : JccAnnotationTestBase() {
9 |
10 | override fun configureByText(text: String): PsiFile =
11 | super.configureByText(text)
12 | .also {
13 | myFixture.enableInspections(inspection)
14 | }
15 | }
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/icons/jjtreeFile.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/COMMON_TOKEN_ACTION.html:
--------------------------------------------------------------------------------
1 | When set to true, every call to the token manager's method getNextToken
2 | (see the description of the Java Compiler Compiler API ) will
3 | cause a call to a used defined method CommonTokenAction after
4 | the token has been scanned in by the token manager. The user
5 | must define this method within the TOKEN_MGR_DECLS section. The
6 | signature of this method is:
7 |
8 | void CommonTokenAction(Token t)
9 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/USER_CHAR_STREAM.html:
--------------------------------------------------------------------------------
1 | By default JavaCC generates a character stream reader as specified
2 | by the options JAVA_UNICODE_ESCAPE and UNICODE_INPUT. The generated
3 | token manager receives characters from this stream reader. If
4 | this option is set to true, then the token manager is generated
5 | to read characters from any character stream reader of type "CharStream.java".
6 | That file is generated into the generated parser directory.
7 |
8 | This option is ignored if {option_link USER_TOKEN_MANAGER} is set to true.
9 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/icons/jjtreeFile_dark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/SANITY_CHECK.html:
--------------------------------------------------------------------------------
1 | Set this option to false to disable some semantic checks when building.
2 | JavaCC performs many syntactic and semantic checks on the grammar file
3 | during parser generation. Some checks such as detection of left
4 | recursion, detection of ambiguity, and bad usage of empty expansions
5 | may be suppressed for faster parser generation. Note that the presence of these errors (even
6 | if they are not detected and reported by setting this option
7 | to false) can cause unexpected behavior from the generated parser
8 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/JccNonTerminalProduction.kt:
--------------------------------------------------------------------------------
1 | // This is a generated file. Not intended for manual editing.
2 | package com.github.oowekyala.ijcc.lang.psi
3 |
4 | interface JccNonTerminalProduction
5 | : JccIdentifierOwner, JjtNodeClassOwner, JccProduction {
6 |
7 | val javaBlock: JccJavaBlock?
8 |
9 | override val jjtreeNodeDescriptor: JccJjtreeNodeDescriptor?
10 |
11 | val header: JccJavaNonTerminalProductionHeader
12 |
13 | override fun getNameIdentifier(): JccIdentifier
14 |
15 | override fun getName(): String
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/jjtree/NODE_FACTORY.html:
--------------------------------------------------------------------------------
1 | Specify a class containing a factory method with following signature to construct nodes:
2 |
3 | public static Node jjtCreate(int id)
4 |
5 |
6 | For backwards compatibility, the value true may also be specified,
7 | meaning that the node class will be used as the factory class, for
8 | each node. This is equivalent to using the string "*"
9 | as a value.
10 |
11 |
If the value is an empty string (or default), the constructor of the
12 | node class will be used instead.
13 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/highlight/JavaccSyntaxHighlighterFactory.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.highlight
2 |
3 | import com.intellij.openapi.fileTypes.SyntaxHighlighter
4 | import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory
5 | import com.intellij.openapi.project.Project
6 | import com.intellij.openapi.vfs.VirtualFile
7 |
8 | /** Extension point. */
9 | class JavaccSyntaxHighlighterFactory : SyntaxHighlighterFactory() {
10 | override fun getSyntaxHighlighter(project: Project?, virtualFile: VirtualFile?): SyntaxHighlighter =
11 | JavaccSyntaxHighlighter()
12 | }
--------------------------------------------------------------------------------
/src/test/resources/com/github/oowekyala/ijcc/lang/parser/fixtures/JjtreeStuff.jjt:
--------------------------------------------------------------------------------
1 | PARSER_BEGIN(JJTreeParser)
2 |
3 | package org.javacc.jjtree;
4 | /**
5 | * This is my parser declaration
6 | */
7 | public class JJTreeParser {
8 |
9 | }
10 |
11 | PARSER_END(JJTreeParser)
12 |
13 |
14 | void parens() #Bar :
15 | {}
16 | {
17 | ("foo" "bar") #Foo
18 | }
19 |
20 | void parens2() #Bar :
21 | {}
22 | {
23 | "a" | ("foo" "bar") #Foo
24 | }
25 |
26 | void parens3() #Bar :
27 | {}
28 | {
29 | "a"
30 | }
31 |
32 | void parens4() #Bar :
33 | {}
34 | {
35 | "a" "b"
36 | }
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/JccIdentifierOwner.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.intellij.psi.PsiElement
4 | import com.intellij.psi.PsiNameIdentifierOwner
5 |
6 | /**
7 | * An element that has an identifier.
8 | *
9 | * @author Clément Fournier
10 | * @since 1.0
11 | */
12 | interface JccIdentifierOwner : JccPsiElement, PsiNameIdentifierOwner {
13 |
14 | override fun getNameIdentifier(): JccIdentifier?
15 |
16 | override fun setName(name: String): PsiElement {
17 | nameIdentifier?.name = name
18 | return this
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/icons/jjtreeNodeLocate.svg:
--------------------------------------------------------------------------------
1 | n
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/icons/jjtreeNodeLocate_dark.svg:
--------------------------------------------------------------------------------
1 | n
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/icons/jjtreeNode_alt.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/test/resources/com/github/oowekyala/ijcc/lang/parser/fixtures/TokenFail.jjt:
--------------------------------------------------------------------------------
1 | PARSER_BEGIN(JJTreeParser)
2 |
3 | package org.javacc.jjtree;
4 | /**
5 | * This is my parser declaration
6 | */
7 | public class JJTreeParser {
8 |
9 | }
10 |
11 | PARSER_END(JJTreeParser)
12 |
13 |
14 | TOKEN :
15 | {
16 | < LEFT_WILDCARD : "*:" >
17 | | < RIGHT_WILDCARD : ":*" >
18 | |
19 | // The actual lexical grammar for NCName is: any name except * ":" *
20 | < NCNAME: "foo" >
21 | |
22 | fo
23 |
24 | }
25 |
26 |
27 | void lookaheads(): {}
28 | {
29 | "fo"
30 |
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/JccNodeExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.github.oowekyala.ijcc.lang.model.AccessModifier
4 |
5 | /*
6 | Miscellaneous semantic extensions for jcc nodes.
7 | */
8 |
9 |
10 |
11 | val JccJavaAccessModifier.modelConstant: AccessModifier
12 | get() = when (text) {
13 | "" -> AccessModifier.PACKAGE_LOCAL
14 | "public" -> AccessModifier.PUBLIC
15 | "protected" -> AccessModifier.PROTECTED
16 | "private" -> AccessModifier.PRIVATE
17 | else -> throw IllegalStateException()
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/model/BaseCachedModelObject.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.model
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.JccFile
4 |
5 | /**
6 | * @author Clément Fournier
7 | * @since 1.2
8 | */
9 | abstract class BaseCachedModelObject(val file: JccFile) {
10 |
11 |
12 | final override fun equals(other: Any?): Boolean =
13 | if (other?.javaClass != javaClass || other !is BaseCachedModelObject) false
14 | else file.virtualFile.path.hashCode() == other.file.virtualFile.path.hashCode()
15 |
16 | final override fun hashCode(): Int = file.virtualFile.path.hashCode()
17 | }
18 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/FORCE_LA_CHECK.html:
--------------------------------------------------------------------------------
1 | This option setting controls lookahead ambiguity checking performed by JavaCC.
2 | By default (when this option is false), lookahead ambiguity checking
3 | is performed for all choice points where the default lookahead
4 | of 1 is used. Lookahead ambiguity checking is not performed at
5 | choice points where there is an explicit lookahead specification,
6 | or if the option {option_link LOOKAHEAD} is set to something other than 1.
7 | Setting this option to true performs lookahead ambiguity checking
8 | at all choice points regardless of the lookahead specifications
9 | in the grammar file.
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/stubs/JccStubElementType.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi.stubs
2 |
3 | import com.github.oowekyala.ijcc.JavaccLanguage
4 | import com.github.oowekyala.ijcc.lang.psi.JccPsiElement
5 | import com.intellij.psi.stubs.IStubElementType
6 | import com.intellij.psi.stubs.StubElement
7 |
8 | /**
9 | * @author Clément Fournier
10 | * @since 1.2
11 | */
12 | abstract class JccStubElementType, TElem : JccPsiElement>(id: String) :
13 | IStubElementType(id, JavaccLanguage.INSTANCE) {
14 |
15 | final override fun getExternalId(): String = "javacc.${super.toString()}"
16 | }
17 |
--------------------------------------------------------------------------------
/.idea/checkstyle-idea.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/JccPsiElement.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.github.oowekyala.ijcc.lang.model.IGrammarOptions
4 | import com.intellij.psi.NavigatablePsiElement
5 |
6 | /**
7 | * Top-level interface for all javacc psi element.
8 | *
9 | * @author Clément Fournier
10 | * @since 1.0
11 | */
12 | interface JccPsiElement : NavigatablePsiElement {
13 |
14 | override fun getContainingFile(): JccFile
15 |
16 | /** Gets the options bundle associated with the grammar this element is found in. */
17 | val grammarOptions: IGrammarOptions
18 | get() = containingFile.grammarOptions
19 |
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/JccScopedExpansionUnit.kt:
--------------------------------------------------------------------------------
1 | // This is a generated file. Not intended for manual editing.
2 | package com.github.oowekyala.ijcc.lang.psi
3 |
4 | import com.github.oowekyala.ijcc.lang.psi.stubs.JccScopedExpansionUnitStub
5 | import com.intellij.psi.StubBasedPsiElement
6 |
7 | interface JccScopedExpansionUnit
8 | : JccIdentifierOwner,
9 | JccExpansionUnit,
10 | JjtNodeClassOwner,
11 | StubBasedPsiElement {
12 |
13 | val expansionUnit: JccExpansionUnit
14 |
15 | override val jjtreeNodeDescriptor: JccJjtreeNodeDescriptor
16 |
17 | override fun getNameIdentifier(): JccIdentifier?
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/util/EnclosedLogger.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.util
2 |
3 | import com.intellij.openapi.diagnostic.Logger
4 |
5 | /**
6 | * Base class for a hidden logger object enclosed in the relevant class.
7 | * Usage:
8 | *
9 | * private object Log : EnclosedLogger()
10 | * // ...
11 | * {
12 | * Log { debug("bla bla") }
13 | * }
14 | */
15 | abstract class EnclosedLogger {
16 |
17 | private val logger = javaClass.enclosingClass
18 | .let { it?.name ?: javaClass.name }
19 | .let { Logger.getInstance(it) }
20 |
21 | operator fun invoke(block: Logger.() -> Unit) = logger.block()
22 |
23 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/JccJjtreeNodeDescriptorExpr.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.github.oowekyala.ijcc.lang.JccTypes
4 |
5 | /**
6 | * Expression in a [JccJjtreeNodeDescriptor].
7 | *
8 | * @author Clément Fournier
9 | * @since 1.0
10 | */
11 | interface JccJjtreeNodeDescriptorExpr : JccPsiElement {
12 |
13 | val isGtExpression: Boolean
14 | // the first child is the parenthesis
15 | get() = firstChild.nextSiblingNoWhitespace?.node?.elementType === JccTypes.JCC_GT
16 |
17 | val javaExpression: JccJavaExpression
18 | }
19 |
20 | val JccJjtreeNodeDescriptorExpr.expressionText: String
21 | get() = javaExpression.text
22 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/impl/GrammarOptionsService.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi.impl
2 |
3 | import com.github.oowekyala.ijcc.lang.model.IGrammarOptions
4 | import com.github.oowekyala.ijcc.lang.model.InlineGrammarOptions
5 | import com.intellij.openapi.project.Project
6 |
7 | /**
8 | * @author Clément Fournier
9 | */
10 | open class GrammarOptionsService {
11 |
12 |
13 | open fun buildOptions(jccFileImpl: JccFileImpl): IGrammarOptions =
14 | InlineGrammarOptions(jccFileImpl)
15 |
16 | }
17 |
18 | val Project.grammarOptionsService: GrammarOptionsService
19 | get() = getComponent(GrammarOptionsService::class.java) ?: GrammarOptionsService() // default
20 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/lang/parser/Jcc21ParserTests.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.parser
2 |
3 | import com.github.oowekyala.ijcc.CongoccParserDefinition
4 | import com.github.oowekyala.ijcc.lang.ParserTestDataPath
5 | import com.intellij.testFramework.ParsingTestCase
6 |
7 | /**
8 | * @author Clément Fournier
9 | * @since 1.6
10 | */
11 | class Jcc21ParserTests : ParsingTestCase("21", "ccc", CongoccParserDefinition()) {
12 |
13 | private val checkIt = true
14 |
15 | // TODO the end is wrong
16 | fun testSimple() = doTest(checkIt)
17 |
18 | override fun getTestDataPath(): String = ParserTestDataPath
19 |
20 | override fun skipSpaces(): Boolean = true
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/findusages/JccTextSelectioner.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.findusages
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.JccIdentifier
4 | import com.github.oowekyala.ijcc.lang.psi.owner
5 | import com.intellij.codeInsight.hint.ImplementationTextSelectioner
6 | import com.intellij.psi.PsiElement
7 |
8 |
9 | class JccTextSelectioner : ImplementationTextSelectioner {
10 | override fun getTextEndOffset(elt: PsiElement): Int =
11 | (elt as? JccIdentifier)?.owner?.textRange?.endOffset
12 | ?: elt.textRange.endOffset
13 |
14 |
15 | override fun getTextStartOffset(element: PsiElement): Int =
16 | element.textRange.startOffset
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/RegexLikeDFVisitor.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | /**
4 | * @author Clément Fournier
5 | * @since 1.0
6 | */
7 | abstract class RegexLikeDFVisitor : DepthFirstVisitor() {
8 |
9 |
10 | abstract override fun visitLiteralRegularExpression(o: JccLiteralRegularExpression)
11 |
12 | abstract override fun visitNamedRegularExpression(o: JccNamedRegularExpression)
13 |
14 | abstract override fun visitEofRegularExpression(o: JccEofRegularExpression)
15 |
16 | abstract override fun visitRefRegularExpression(o: JccRefRegularExpression)
17 |
18 | abstract override fun visitContainerRegularExpression(o: JccContainerRegularExpression)
19 |
20 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/stubs/indices/IdeStubService.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi.stubs.indices
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.stubs.JjtNodeClassOwnerStub
4 | import com.github.oowekyala.ijcc.lang.psi.stubs.StubIndexService
5 | import com.github.oowekyala.ijcc.util.runIt
6 | import com.intellij.psi.stubs.IndexSink
7 |
8 | /**
9 | * @author Clément Fournier
10 | */
11 | class IdeStubService : StubIndexService() {
12 |
13 | override fun indexJjtreeNodeClassOwner(stub: JjtNodeClassOwnerStub<*>, sink: IndexSink) {
14 | stub.jjtNodeQualifiedName?.runIt {
15 | sink.occurrence(JjtreeQNameStubIndex.key, it)
16 | }
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/completion/LookupUtil.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.completion
2 |
3 | import com.intellij.codeInsight.TailType
4 | import com.intellij.codeInsight.completion.PrioritizedLookupElement
5 | import com.intellij.codeInsight.lookup.LookupElement
6 | import com.intellij.codeInsight.lookup.TailTypeDecorator
7 |
8 |
9 | fun LookupElement.withTail(tail: String): LookupElement =
10 | TailTypeDecorator.withTail(this, MultiCharTailType(tail))
11 |
12 | fun LookupElement.withTail(tailType: TailType): LookupElement =
13 | TailTypeDecorator.withTail(this, tailType)
14 |
15 | fun LookupElement.withPriority(priority: Double): LookupElement =
16 | PrioritizedLookupElement.withPriority(this, priority)
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/lang/JccFoldingBuilderTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang
2 |
3 | import com.github.oowekyala.ijcc.lang.util.JccTestBase
4 |
5 | /**
6 | * @author Clément Fournier
7 | * @since 1.0
8 | */
9 | class JccFoldingBuilderTest : JccTestBase() {
10 |
11 |
12 | override fun getTestDataPath(): String = TestResourcesPath
13 |
14 | fun testFolding() {
15 | myFixture.configureByFiles()
16 | myFixture.testFoldingWithCollapseStatus("$FoldingTestDataPath/ParserActions.jjt")
17 | }
18 |
19 | fun testFoldingJjtreeGen() {
20 | myFixture.configureByFiles()
21 | myFixture.testFoldingWithCollapseStatus("$FoldingTestDataPath/JjtreeGen.jj")
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/JccTypesExt.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.github.oowekyala.ijcc.lang.JccTypes
4 | import com.github.oowekyala.ijcc.lang.JccTypes.*
5 | import com.intellij.psi.TokenType
6 | import com.intellij.psi.tree.TokenSet
7 |
8 | /**
9 | * @author Clément Fournier
10 | * @since 1.0
11 | */
12 | object JccTypesExt : JccTypes {
13 |
14 | val IdentifierTypeSet = TokenSet.create(JCC_IDENT)
15 |
16 | val CommentTypeSet = TokenSet.create(
17 | JCC_END_OF_LINE_COMMENT,
18 | JCC_C_STYLE_COMMENT
19 | )
20 |
21 | val StringLiteralTypeSet = TokenSet.create(JCC_STRING_LITERAL)
22 |
23 | val WhitespaceTypeSet = TokenSet.create(TokenType.WHITE_SPACE)
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/stubs/DataStreamUtils.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi.stubs
2 |
3 | import com.intellij.util.io.DataInputOutputUtil
4 | import java.io.DataInputStream
5 | import java.io.DataOutputStream
6 |
7 | inline fun >
8 | DataInputStream.readEnum(): T = T::class.java.enumConstants[readInt()]
9 |
10 | fun > DataOutputStream.writeEnum(t: T) = writeInt(t.ordinal)
11 |
12 | fun DataOutputStream.writeNullable(t: T?, writer: DataOutputStream.(T) -> Unit): Unit =
13 | DataInputOutputUtil.writeNullable(this, t) { writer(this, it) }
14 |
15 | fun DataInputStream.readNullable(reader: DataInputStream.() -> T): T? =
16 | DataInputOutputUtil.readNullable(this) { reader(this) }
17 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/model/JccVersion.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.model
2 |
3 | /**
4 | * Version of Javacc, based on the versions published to maven.
5 | *
6 | * @author Clément Fournier
7 | * @since 1.0
8 | */
9 | enum class JccVersion {
10 | V_2_1, //
11 | V_3_2, // Mar, 2006
12 | V_4_0, // Mar, 2006
13 | V_4_1, // Oct, 2008
14 | V_4_2, // Feb, 2009
15 | V_5_0, // Sep, 2009
16 | V_6_1_0, // Apr, 2014
17 | V_6_1_1, // May, 2014
18 | V_6_1_2, // May, 2014
19 | V_7_0_0, // Dec, 2016
20 | V_7_0_1, // Jan, 2017
21 | V_7_0_2, // Jan, 2017
22 | V_7_0_3, // Nov, 2017
23 | V_7_0_4; // Sep, 2018
24 |
25 | companion object {
26 | val Latest = values().last()
27 | }
28 | }
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/icons/jccNavigateToNode.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/icons/jccNavigateToNode_dark.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/icons/JccCoreIcons.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.icons
2 |
3 | import com.intellij.openapi.util.IconLoader
4 | import javax.swing.Icon
5 |
6 | /**
7 | * These icons should *not* depend on icons.jar, ie
8 | * not use AllIcons and only use icons shipped in this jar.
9 | */
10 | enum class JccCoreIcons(icon: Icon) : Icon by icon {
11 |
12 | /** File type icon. */
13 | JAVACC_FILE("jccFile.svg"),
14 | JJTREE_FILE("jjtreeFile.svg"),
15 | JJTRICKS_FILE("jjtreeFile.svg"),
16 | ;
17 |
18 | constructor(fname: String) : this(IconLoader.getIcon(fname, JccCoreIcons::class.java))
19 |
20 | companion object {
21 |
22 | fun default(): Icon = IconLoader.getIcon("jjtreeNodeLocate.svg", JccCoreIcons::class.java)
23 | }
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/stubs/StubIndexService.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi.stubs
2 |
3 | import com.intellij.openapi.application.ApplicationManager
4 | import com.intellij.psi.stubs.IndexSink
5 |
6 | /**
7 | * Overridable stub service, implemented by the plugin.
8 | *
9 | * @author Clément Fournier
10 | */
11 | open class StubIndexService protected constructor() {
12 |
13 | open fun indexJjtreeNodeClassOwner(stub: JjtNodeClassOwnerStub<*>, sink: IndexSink) {
14 | }
15 |
16 | companion object {
17 | @JvmStatic
18 | fun getInstance(): StubIndexService =
19 | ApplicationManager.getApplication().getService(StubIndexService::class.java) ?: NO_INDEX
20 |
21 | private val NO_INDEX = StubIndexService()
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/injection/InjectionUtil.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.injection
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.JccGrammarFileRoot
4 | import com.intellij.openapi.util.Key
5 |
6 |
7 | private fun getLinearStructureFor(grammarFileRoot: JccGrammarFileRoot): LinearInjectedStructure =
8 | TreeLineariserVisitor.linearise(InjectedTreeBuilderVisitor.getInjectedSubtreeFor(grammarFileRoot))
9 |
10 | private val LinearStructureKey = Key.create("linearInjectedStructure")
11 |
12 | val JccGrammarFileRoot.linearInjectedStructure: LinearInjectedStructure
13 | get() = getUserData(LinearStructureKey)
14 | ?: getLinearStructureFor(this)
15 | .also {
16 | // putUserData(LinearStructureKey, it)
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/ide/highlight/JccRichHighlightTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.highlight
2 |
3 | import com.github.oowekyala.ijcc.util.JccAnnotationTestBase
4 | import org.junit.Ignore
5 |
6 | /**
7 | * FIXME info annots are not checked!
8 | *
9 | * @author Clément Fournier
10 | * @since 1.0
11 | */
12 | @Ignore
13 | class JccRichHighlightTest : JccAnnotationTestBase() {
14 |
15 |
16 | fun testNormalRegexLiteralReference() = checkByText(
17 | """
18 | TOKEN: {
19 |
20 | }
21 |
22 | void Foo():{} {
23 | "foo"
24 | }
25 | """.inGrammarCtx(),
26 | checkInfo = true
27 | )
28 |
29 |
30 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/findusages/JccDescriptionProvider.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.findusages
2 |
3 | import com.intellij.psi.ElementDescriptionLocation
4 | import com.intellij.psi.ElementDescriptionProvider
5 | import com.intellij.psi.PsiElement
6 | import com.intellij.usageView.UsageViewLongNameLocation
7 |
8 | import com.github.oowekyala.ijcc.lang.psi.JccPsiElement
9 |
10 | /**
11 | * Describes elements for the usage view. (TODO)
12 | *
13 | * @author Clément Fournier
14 | * @since 1.0
15 | */
16 | class JccDescriptionProvider : ElementDescriptionProvider {
17 | override fun getElementDescription(element: PsiElement, location: ElementDescriptionLocation): String? =
18 | if (element is JccPsiElement && location is UsageViewLongNameLocation) element.text
19 | else null
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/util/SoftReferenceCache.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.util
2 |
3 | import java.lang.ref.Reference
4 | import java.lang.ref.SoftReference
5 | import kotlin.reflect.KProperty
6 |
7 | /**
8 | * Delegated property type.
9 | *
10 | * @author Clément Fournier
11 | * @since 1.0
12 | */
13 | class SoftReferenceCache(private val supplier: () -> T) {
14 |
15 | private var ref: Reference? = null
16 |
17 | operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
18 | val cached = ref?.get()
19 | return if (cached == null) {
20 | val result = supplier()
21 | ref = SoftReference(result)
22 | return result
23 | } else cached
24 | }
25 |
26 | }
27 |
28 |
29 | fun softCache(supplier: () -> T) = SoftReferenceCache(supplier)
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/CHOICE_AMBIGUITY_CHECK.html:
--------------------------------------------------------------------------------
1 | This is the number of tokens considered in checking choices
2 | of the form A | B | ... for ambiguity.
3 |
4 | For example, if there is a common two token prefix for both A
5 | and B, but no common three token prefix, (assume this option
6 | is set to 3) then JavaCC can tell you to use a lookahead of 3 for disambiguation
7 | purposes. And if A and B have a common three token prefix, then JavaCC only
8 | tell you that you need to have a lookahead of 3 or more. Increasing this can
9 | give you more comprehensive ambiguity information at the cost of more processing
10 | time. For large grammars such as the Java grammar, increasing this number any
11 | further causes the checking to take too much time.
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/stubs/indices/JjtreeQNameStubIndex.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi.stubs.indices
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.JjtNodeClassOwner
4 | import com.intellij.psi.stubs.StringStubIndexExtension
5 | import com.intellij.psi.stubs.StubIndexKey
6 |
7 | /**
8 | * Indexes the node class owners of a grammar by qname, to provide
9 | * links from the node classes to the productions.
10 | *
11 | * @author Clément Fournier
12 | * @since 1.2
13 | */
14 | object JjtreeQNameStubIndex : StringStubIndexExtension() {
15 |
16 | private val Key = StubIndexKey.createIndexKey("jjtree.qname.owner")
17 |
18 | override fun getKey(): StubIndexKey = Key
19 |
20 | override fun getVersion(): Int = 1
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/injection/MultilineTextEscaper.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.injection
2 |
3 | import com.intellij.openapi.util.TextRange
4 | import com.intellij.psi.LiteralTextEscaper
5 | import com.intellij.psi.PsiLanguageInjectionHost
6 |
7 | /**
8 | * @author Clément Fournier
9 | * @since 1.0
10 | */
11 | class MultilineTextEscaper(t: T) : LiteralTextEscaper(t) {
12 | override fun isOneLine(): Boolean = false
13 |
14 | override fun decode(rangeInsideHost: TextRange, outChars: StringBuilder): Boolean {
15 | outChars.append(rangeInsideHost.substring(myHost.text))
16 | return true
17 | }
18 |
19 | override fun getOffsetInHost(offsetInDecoded: Int, rangeInsideHost: TextRange): Int {
20 | return rangeInsideHost.startOffset + offsetInDecoded
21 | }
22 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/completion/MultiCharTailType.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.completion
2 |
3 | import com.intellij.codeInsight.TailType
4 | import com.intellij.openapi.editor.Editor
5 |
6 | /**
7 | * @author Clément Fournier
8 | * @since 1.1
9 | */
10 | data class MultiCharTailType(private val tail: String) : TailType() {
11 |
12 | override fun processTail(editor: Editor, tailOffset: Int): Int {
13 |
14 | val document = editor.document
15 |
16 | var finalOffset = tailOffset
17 | for (char in tail) {
18 |
19 | finalOffset = when (char) {
20 | document.charsSequence[tailOffset] -> moveCaret(editor, finalOffset, 1)
21 | else -> insertChar(editor, finalOffset, char)
22 | }
23 | }
24 |
25 | return finalOffset
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Run_plugin_in_sandbox.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | true
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/lang/ParserTestDsl.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang
2 |
3 | import com.github.oowekyala.ijcc.lang.util.AssertionMatcher
4 | import com.github.oowekyala.ijcc.lang.util.JccTestBase
5 | import com.github.oowekyala.ijcc.lang.util.PsiSpec
6 | import com.github.oowekyala.ijcc.lang.util.matchPsi
7 | import com.intellij.psi.PsiElement
8 | import io.kotest.matchers.should
9 |
10 | /**
11 | * @author Clément Fournier
12 | * @since 1.0
13 | */
14 |
15 |
16 | abstract class ParserTestDsl : JccTestBase() {
17 |
18 |
19 | protected inline fun matchExpansion(ignoreChildren: Boolean = false,
20 | noinline nodeSpec: PsiSpec): AssertionMatcher =
21 | {
22 | it.asExpansion() should matchPsi(ignoreChildren, nodeSpec)
23 | }
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/refs/JccLexicalStateReference.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.refs
2 |
3 | import com.github.oowekyala.ijcc.lang.model.LexicalState
4 | import com.github.oowekyala.ijcc.lang.psi.JccIdentifier
5 | import com.intellij.psi.PsiElement
6 | import com.intellij.psi.PsiReferenceBase
7 |
8 | /**
9 | * @author Clément Fournier
10 | * @since 1.2
11 | */
12 | class JccLexicalStateReference(element: JccIdentifier) : PsiReferenceBase(element) {
13 |
14 | override fun resolve(): PsiElement? = resolveState()?.declarationIdent
15 |
16 | fun resolveState(): LexicalState? =
17 | element.containingFile
18 | .lexicalGrammar
19 | .getLexicalState(element.name)
20 |
21 |
22 | override fun getVariants(): Array =
23 | JccRefVariantService.getInstance(element.project).lexicalStateVariants(this)
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/cfa/LastExpansion.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.cfa
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.JccExpansion
4 | import com.github.oowekyala.ijcc.lang.psi.JccExpansionSequence
5 | import com.intellij.psi.PsiElement
6 |
7 | /**
8 | * Given that [bound] is an ancestor of this expansion,
9 | * finds out if [this] is executed last when executing
10 | * the [bound]. This is used to find the last expansion
11 | * of a node scope.
12 | */
13 | fun JccExpansion.isNextStep(bound: PsiElement): Boolean {
14 | val parent = parent
15 |
16 | return when {
17 | this == bound -> true
18 | parent is JccExpansionSequence -> parent.expansionUnitList.last() == this && parent.isNextStep(bound)
19 | parent is JccExpansion -> parent.isNextStep(bound)
20 | else -> parent == bound
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/JccJavaBlock.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.github.oowekyala.ijcc.lang.injection.HostSpec
4 | import com.github.oowekyala.ijcc.lang.injection.MultilineTextEscaper
5 | import com.github.oowekyala.ijcc.lang.psi.impl.jccEltFactory
6 | import com.intellij.psi.LiteralTextEscaper
7 | import com.intellij.psi.PsiLanguageInjectionHost
8 |
9 | interface JccJavaBlock : JccPsiElement, PsiLanguageInjectionHost {
10 |
11 | override fun isValidHost(): Boolean = true
12 |
13 | override fun updateText(text: String): PsiLanguageInjectionHost =
14 | this.replace(project.jccEltFactory.createJavaBlock(text))
15 | .let { it as PsiLanguageInjectionHost }
16 | .also { HostSpec.replaceHost(this, it) }
17 |
18 | override fun createLiteralTextEscaper(): LiteralTextEscaper =
19 | MultilineTextEscaper(this)
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/gutter/BaseTargetingLineMarkerProvider.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.gutter
2 |
3 | import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo
4 | import com.intellij.codeInsight.daemon.RelatedItemLineMarkerProvider
5 | import com.intellij.psi.PsiElement
6 |
7 | /**
8 | * @author Clément Fournier
9 | * @since 1.2
10 | */
11 | abstract class BaseTargetingLineMarkerProvider(private val target: Class)
12 | : RelatedItemLineMarkerProvider() {
13 |
14 |
15 | final override fun collectNavigationMarkers(element: PsiElement, result: MutableCollection>) {
16 |
17 | element.takeIf { target.isInstance(it) }
18 | ?.let { target.cast(it) }
19 | ?.let { processElt(it) }
20 | ?.forEach { result.add(it) }
21 | }
22 |
23 | abstract fun processElt(elt: T): Sequence>
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/JccJavaExpression.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.github.oowekyala.ijcc.lang.injection.HostSpec
4 | import com.github.oowekyala.ijcc.lang.injection.MultilineTextEscaper
5 | import com.github.oowekyala.ijcc.lang.psi.impl.jccEltFactory
6 | import com.intellij.psi.LiteralTextEscaper
7 | import com.intellij.psi.PsiLanguageInjectionHost
8 |
9 | interface JccJavaExpression : JccPsiElement, PsiLanguageInjectionHost {
10 |
11 |
12 | override fun isValidHost(): Boolean = true
13 |
14 | override fun updateText(text: String): PsiLanguageInjectionHost =
15 | this.replace(project.jccEltFactory.createJavaExpression(text))
16 | .let { it as PsiLanguageInjectionHost }
17 | .also { HostSpec.replaceHost(this, it) }
18 |
19 |
20 | override fun createLiteralTextEscaper(): LiteralTextEscaper =
21 | MultilineTextEscaper(this)
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/highlight/JavaccSyntaxHighlighter.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.highlight
2 |
3 | import com.github.oowekyala.ijcc.lang.lexer.JavaccLexerAdapter
4 | import com.intellij.lexer.Lexer
5 | import com.intellij.openapi.editor.colors.TextAttributesKey
6 | import com.intellij.openapi.fileTypes.SyntaxHighlighterBase
7 | import com.intellij.psi.tree.IElementType
8 |
9 | /**
10 | * Syntax highlighter.
11 | *
12 | * @author Clément Fournier
13 | * @since 1.0
14 | */
15 | class JavaccSyntaxHighlighter : SyntaxHighlighterBase() {
16 | override fun getTokenHighlights(tokenType: IElementType?): Array {
17 | val highlight =
18 | JavaccHighlightingColors.getTokenHighlight(tokenType)
19 | return when (highlight) {
20 | null -> emptyArray()
21 | else -> arrayOf(highlight)
22 | }
23 | }
24 |
25 |
26 | override fun getHighlightingLexer(): Lexer = JavaccLexerAdapter()
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/JccJavaCompilationUnit.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.github.oowekyala.ijcc.lang.injection.MultilineTextEscaper
4 | import com.intellij.psi.ElementManipulators
5 | import com.intellij.psi.LiteralTextEscaper
6 | import com.intellij.psi.PsiLanguageInjectionHost
7 |
8 | interface JccJavaCompilationUnit : PsiLanguageInjectionHost, JccPsiElement {
9 | override fun updateText(text: String): PsiLanguageInjectionHost =
10 | this.also {
11 | ElementManipulators.handleContentChange(this, text)
12 | }
13 | // this.replace(project.jccEltFactory.createJcu(text))
14 | // .let { it as PsiLanguageInjectionHost }
15 | // .also { HostSpec.replaceHost(this, it) }
16 |
17 | override fun createLiteralTextEscaper(): LiteralTextEscaper =
18 | MultilineTextEscaper(this)
19 |
20 | override fun isValidHost(): Boolean = true
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/JccJavaAssignmentLhs.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.github.oowekyala.ijcc.lang.injection.HostSpec
4 | import com.github.oowekyala.ijcc.lang.injection.MultilineTextEscaper
5 | import com.github.oowekyala.ijcc.lang.psi.impl.jccEltFactory
6 | import com.intellij.psi.LiteralTextEscaper
7 | import com.intellij.psi.PsiLanguageInjectionHost
8 |
9 | interface JccJavaAssignmentLhs : JccPsiElement, PsiLanguageInjectionHost {
10 |
11 | val javaName: JccJavaName
12 |
13 | override fun isValidHost(): Boolean = true
14 |
15 | override fun updateText(text: String): PsiLanguageInjectionHost =
16 | this.replace(project.jccEltFactory.createAssignmentLhs(text))
17 | .let { it as PsiLanguageInjectionHost }
18 | .also { HostSpec.replaceHost(this, it) }
19 |
20 |
21 | override fun createLiteralTextEscaper(): LiteralTextEscaper =
22 | MultilineTextEscaper(this)
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/settings/JavaccProjectSettingsServiceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.settings
2 |
3 | import com.github.oowekyala.ijcc.settings.JavaccProjectSettingsService.JccSettingsState
4 | import com.intellij.openapi.components.PersistentStateComponent
5 | import com.intellij.openapi.components.State
6 |
7 | /**
8 | * @author Clément Fournier
9 | * @since 1.0
10 | */
11 | @State(name = "JavaccProjectSettings") // use misc.xml
12 | class JavaccProjectSettingsServiceImpl : JavaccProjectSettingsService,
13 | PersistentStateComponent {
14 |
15 | override var myState = JccSettingsState()
16 |
17 | override fun getState(): JavaccProjectSettingsService.PersistableSettingsState = myState.toMutable()
18 |
19 | override fun loadState(state: JavaccProjectSettingsService.PersistableSettingsState) {
20 | myState = state.toImmutable()
21 | }
22 |
23 | // TODO notify bus when the injection level changes?
24 | }
25 |
--------------------------------------------------------------------------------
/src/test/resources/com/github/oowekyala/ijcc/lang/parser/fixtures/JavaTypes.jjt:
--------------------------------------------------------------------------------
1 | PARSER_BEGIN(JJTreeParser)
2 |
3 | package org.javacc.jjtree;
4 | /**
5 | * This is my parser declaration
6 | */
7 | public class JJTreeParser {
8 |
9 | }
10 |
11 | PARSER_END(JJTreeParser)
12 |
13 |
14 |
15 | void emptyAlt(List generic): {}
16 | {
17 | "f"
18 | }
19 |
20 | Frab emptyAlt2(List generic): {}
21 | {
22 | "f"
23 | }
24 |
25 | Frab emptyAlt9(List generic): {}
26 | {
27 | "f"
28 | }
29 |
30 | Frab extends Bar> emptyAlt3(List... generic): {}
31 | {
32 | "f"
33 | }
34 |
35 | Frab> emptyAlt4(List... generic): {}
36 | {
37 | "f"
38 | }
39 |
40 | Frab>[] emptyAlt5(List... generic): {}
41 | {
42 | "f"
43 | }
44 |
45 | Frab>[] emptyAlt6(List[] generic): {}
46 | {
47 | "f"
48 | }
49 |
50 | Frab>[] emptyAlt7(List[] generic): {}
51 | {
52 | "f"
53 | }
54 | Frab>[] emptyAlt8(List[] generic): {}
55 | {
56 | "f"
57 | }
58 |
--------------------------------------------------------------------------------
/src/test/resources/com/github/oowekyala/ijcc/lang/parser/fixtures/Lookaheads.jjt:
--------------------------------------------------------------------------------
1 | PARSER_BEGIN(JJTreeParser)
2 |
3 | package org.javacc.jjtree;
4 | /**
5 | * This is my parser declaration
6 | */
7 | public class JJTreeParser {
8 |
9 | }
10 |
11 | PARSER_END(JJTreeParser)
12 |
13 |
14 |
15 | void lookaheads(): {}
16 | {
17 | LOOKAHEAD(1, ID(), {getToken(1).kind != NATURAL}) // lexical, syntactic, semantic
18 | LOOKAHEAD({getToken(1).kind != NATURAL}) // semantic, not syntactic
19 | LOOKAHEAD(1) // lexical
20 | LOOKAHEAD(TableAlias(), {getToken(1).kind != NATURAL}) // syntactic, semantic
21 | LOOKAHEAD(1, ("foo" | "bar") ) // lexical, syntactic
22 |
23 | LOOKAHEAD({ doSth(); }, {getToken(1).kind != NATURAL}) // invalid parse
24 |
25 | "f" | "fk" // FIXME shouldn't be affected
26 | }
27 |
28 | // shouldn't be affected by the failed lookahead above
29 | void foo(): {} {
30 | "a" | "b"
31 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/refs/JccRefVariantService.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.refs
2 |
3 | import com.intellij.openapi.project.Project
4 |
5 | /**
6 | * @author Clément Fournier
7 | */
8 | open class JccRefVariantService {
9 |
10 |
11 | open fun nonterminalRefVariants(ref: JccNonTerminalReference): Array = emptyArray()
12 | open fun terminalVariants(ref: JccTerminalReference): Array = emptyArray()
13 | open fun lexicalStateVariants(ref: JccLexicalStateReference): Array = emptyArray()
14 | open fun stringLiteralVariants(ref: JccBnfStringLiteralReference): Array = emptyArray()
15 | open fun jjtreeNodeVariants(ref: JjtNodePolyReference): Array = emptyArray()
16 |
17 |
18 | companion object {
19 | @JvmStatic
20 | fun getInstance(project: Project): JccRefVariantService =
21 | project.getService(JccRefVariantService::class.java) ?: NO_VARIANTS
22 |
23 | private val NO_VARIANTS = JccRefVariantService()
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/LookaheadExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | /*
4 |
5 | void lookaheads(): {}
6 | {
7 | LOOKAHEAD(1, ID(), {getToken(1).kind != NATURAL}) // lexical, syntactic, semantic
8 | LOOKAHEAD({getToken(1).kind != NATURAL}) // semantic, not syntactic
9 | LOOKAHEAD(1) // lexical
10 | LOOKAHEAD(TableAlias(), {getToken(1).kind != NATURAL}) // syntactic, semantic
11 | LOOKAHEAD(1, ("foo" | "bar") ) // lexical, syntactic
12 |
13 | LOOKAHEAD({ doSth(); }, {getToken(1).kind != NATURAL}) // invalid parse
14 | }
15 | */
16 | val JccLocalLookaheadUnit.isLexical
17 | get() = integerLiteral != null
18 |
19 | val JccLocalLookaheadUnit.isSyntactic
20 | get() = expansion != null
21 |
22 | val JccLocalLookaheadUnit.isSemantic
23 | get() = javaExpression != null
24 |
25 | val JccLocalLookaheadUnit.lexicalAmount: Int?
26 | get() = integerLiteral?.text?.toInt()
27 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/ide/inspections/ActionsWithinLookaheadInspectionTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.inspections
2 |
3 | import com.github.oowekyala.ijcc.ide.inspections.ActionWithinLookaheadInspection.Companion.ProblemDescription
4 |
5 | /**
6 | * @author Clément Fournier
7 | * @since 1.0
8 | */
9 | class ActionsWithinLookaheadInspectionTest : JccInspectionTestBase(ActionWithinLookaheadInspection()) {
10 |
11 | private fun ignored(s: String) = warningAnnot(s, ProblemDescription)
12 |
13 | fun testPos() = checkByText(
14 | """
15 | LOOKAHEAD(4,Foo() ${ignored("{}")})
16 | """.inExpansionCtx("Foo")
17 | )
18 |
19 | fun testNeg() = checkByText(
20 | """
21 | LOOKAHEAD(4,Foo() ${ignored("{}")}) {}
22 | """.inExpansionCtx("Foo")
23 | )
24 |
25 | fun testNestedSyntactic() = checkByText(
26 | """
27 | (LOOKAHEAD(1, "f" | LOOKAHEAD(4,Foo()${ignored("{}")}) Foo()) "foo")?
28 | """.inExpansionCtx("Foo")
29 | )
30 |
31 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/impl/JccRegexExpansionUnitImpl.kt:
--------------------------------------------------------------------------------
1 | // This is a generated file. Not intended for manual editing.
2 | package com.github.oowekyala.ijcc.lang.psi.impl
3 |
4 | import com.github.oowekyala.ijcc.lang.psi.*
5 | import com.intellij.lang.ASTNode
6 | import com.intellij.psi.PsiElementVisitor
7 |
8 | class JccRegexExpansionUnitImpl(node: ASTNode) : JccAssignableExpansionUnitImpl(node), JccRegexExpansionUnit {
9 |
10 | override fun accept(visitor: JccVisitor) {
11 | visitor.visitRegexExpansionUnit(this)
12 | }
13 |
14 | override fun accept(visitor: PsiElementVisitor) {
15 | if (visitor is JccVisitor)
16 | accept(visitor)
17 | else
18 | super.accept(visitor)
19 | }
20 |
21 | override fun getRegularExpression(): JccRegularExpression =
22 | findNotNullChildByClass(JccRegularExpression::class.java)
23 |
24 | override fun getNameIdentifier(): JccIdentifier? = (regularExpression as? JccNamedRegularExpression)?.nameIdentifier
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/JccIdentifier.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.intellij.psi.PsiElement
4 | import com.intellij.psi.PsiNamedElement
5 |
6 | interface JccIdentifier : JccPsiElement, PsiNamedElement {
7 |
8 | override fun getName(): String
9 |
10 | val leaf: PsiElement
11 | }
12 |
13 | val JccIdentifier.owner: JccIdentifierOwner?
14 | get() =
15 | ancestors(includeSelf = false)
16 | .takeWhile { it is JccIdentifierOwner }
17 | .filterIsInstance()
18 | .lastOrNull { it.nameIdentifier == this }
19 |
20 |
21 | val JccIdentifier.isJjtreeNodeIdentifier: Boolean
22 | get() = parent is JccJjtreeNodeDescriptor
23 | || (parent as? JccJavaNonTerminalProductionHeader)
24 | ?.let { it.parent as JccNonTerminalProduction }
25 | ?.let { it.nameIdentifier == it.nodeIdentifier } == true
26 |
27 | val JccIdentifier.isLexicalStateName: Boolean
28 | get() = parent is JccLexicalStateList || parent is JccRegexSpec
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/rename/JccNamesValidator.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.rename
2 |
3 | import com.intellij.lang.refactoring.JavaNamesValidator
4 | import com.intellij.openapi.project.Project
5 |
6 | /**
7 | * Validates names for the rename refactoring.
8 | *
9 | * @author Clément Fournier
10 | * @since 1.0
11 | */
12 | class JccNamesValidator : JavaNamesValidator() {
13 | private val jccKeywords = listOf(
14 | "LOOKAHEAD",
15 | "IGNORE_CASE",
16 | "PARSER_BEGIN",
17 | "PARSER_END",
18 | "JAVACODE",
19 | "TOKEN",
20 | "SPECIAL_TOKEN",
21 | "MORE",
22 | "SKIP",
23 | "TOKEN_MGR_DECLS",
24 | "EOF"
25 | )
26 |
27 | override fun isKeyword(name: String, project: Project?): Boolean =
28 | jccKeywords.contains(name) || super.isKeyword(name, project)
29 |
30 | override fun isIdentifier(name: String, project: Project?): Boolean =
31 | !jccKeywords.contains(name) && super.isIdentifier(name, project)
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/manipulators/JccIdentifierManipulator.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi.manipulators
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.JccIdentifier
4 | import com.github.oowekyala.ijcc.lang.psi.impl.jccEltFactory
5 | import com.intellij.openapi.util.TextRange
6 | import com.intellij.psi.AbstractElementManipulator
7 | import com.intellij.util.IncorrectOperationException
8 |
9 |
10 | /**
11 | * @author Clément Fournier
12 | * @since 1.0
13 | */
14 | class JccIdentifierManipulator : AbstractElementManipulator() {
15 | @Throws(IncorrectOperationException::class)
16 | override fun handleContentChange(identifier: JccIdentifier, range: TextRange, newContent: String): JccIdentifier {
17 | val oldText = identifier.text
18 | val newText = oldText.substring(0, range.startOffset) + newContent +
19 | oldText.substring(range.endOffset)
20 | return identifier.replace(identifier.project.jccEltFactory.createIdentifier(newText)) as JccIdentifier
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/PrettyPrintingExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | /**
4 | * TODO
5 | * @author Clément Fournier
6 | * @since 1.0
7 | */
8 | fun JccPsiElement.foldingName(): String = when (this) {
9 | is JccOptionalExpansionUnit -> "[...]"
10 | is JccParenthesizedExpansionUnit -> "(...)" + occurrenceIndicator.foldingName()
11 | is JccOptionSection -> "options {..}"
12 | is JccParserDeclaration -> "/PARSER DECLARATION/"
13 | is JccTokenManagerDecls -> "/TOKEN MANAGER DECLARATIONS/"
14 | is JccRegexProduction -> "${regexKind.text}: {..}"
15 | is JccLocalLookaheadUnit -> {
16 | if (isLexical && !isSyntactic && !isSemantic) {
17 | "LOOKAHEAD($lexicalAmount)"
18 | } else "LOOKAHEAD(_)" // use one char instead of .. for alignment
19 | }
20 |
21 | is JccParserActionsUnit -> "{..}"
22 |
23 |
24 | else -> text
25 | }
26 |
27 |
28 | fun JccOccurrenceIndicator?.foldingName() = this?.text ?: ""
29 |
30 |
--------------------------------------------------------------------------------
/src/test/resources/com/github/oowekyala/ijcc/lang/folding/fixtures/ParserActions.jjt:
--------------------------------------------------------------------------------
1 | PARSER_BEGIN(JJTreeParser)
2 | PARSER_END(JJTreeParser)
3 |
4 | SKIP : {
5 | "(:" { commentNestingDepth++; }
6 | }
7 |
8 |
9 | void QuantifiedExpr():
10 | {}
11 | {
12 | ( { jjtThis.setUniversallyQuantified(false); } )
13 | VarBindingList(false)
14 | ExprSingle()
15 | }
16 |
17 | JAVACODE
18 | void node_descriptor_expression() #NodeDescriptorExpression
19 | {
20 | Token tok;
21 | int nesting = 1;
22 | while (true) {
23 | tok = getToken(1);
24 | if (tok.kind == 0) {
25 | throw new ParseException();
26 | }
27 | if (tok.kind == LPAREN) nesting++;
28 | if (tok.kind == RPAREN) {
29 | nesting--;
30 | if (nesting == 0) break;
31 | }
32 | tok = getNextToken();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Clément Fournier
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/structureview/JavaccStructureViewBuilderFactory.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.structureview
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.impl.JccFileImpl
4 | import com.intellij.ide.structureView.StructureViewBuilder
5 | import com.intellij.ide.structureView.StructureViewModel
6 | import com.intellij.ide.structureView.TreeBasedStructureViewBuilder
7 | import com.intellij.lang.PsiStructureViewFactory
8 | import com.intellij.openapi.editor.Editor
9 | import com.intellij.psi.PsiFile
10 |
11 | class JavaccStructureViewBuilderFactory : PsiStructureViewFactory {
12 |
13 | override fun getStructureViewBuilder(psiFile: PsiFile): StructureViewBuilder? {
14 | return when (psiFile) {
15 | !is JccFileImpl -> null
16 | else -> object : TreeBasedStructureViewBuilder() {
17 |
18 | override fun isRootNodeShown(): Boolean = false
19 |
20 | override fun createStructureViewModel(editor: Editor?): StructureViewModel =
21 | JavaccFileStructureViewModel(psiFile)
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/model/J21Option.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.model
2 |
3 | import com.github.oowekyala.ijcc.lang.model.JccOptionType.BaseOptionType.*
4 |
5 | /**
6 | * @author Clément Fournier
7 | * @since 1.0
8 | */
9 | @Suppress("ClassName", "unused")
10 | sealed class J21Option(type: JccOptionType, staticDefaultValue: T?)
11 | : GenericOption(type, staticDefaultValue, GrammarNature.JJTREE) {
12 |
13 | override val name: String = javaClass.simpleName
14 |
15 | object SPECIAL_TOKENS_ARE_NODES : J21Option(BOOLEAN, false)
16 |
17 | object DEFAULT_LEXICAL_STATE : J21Option(STRING, "DEFAULT")
18 | object TABS_TO_SPACE : J21Option(INTEGER, 4)
19 |
20 | /*
21 | SPECIAL_TOKENS_ARE_NODES;
22 | PARSER_PACKAGE=javagrammar;
23 | DEFAULT_LEXICAL_STATE=JAVA;
24 | PRESERVE_LINE_ENDINGS=false;
25 | TABS_TO_SPACES=8;
26 | */
27 |
28 | companion object {
29 | val values = listOf(
30 | SPECIAL_TOKENS_ARE_NODES,
31 | DEFAULT_LEXICAL_STATE,
32 | TABS_TO_SPACE
33 | )
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/ide/inspections/UnnamedRegexInspectionTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.inspections
2 |
3 | /**
4 | * @author Clément Fournier
5 | * @since 1.0
6 | */
7 | class UnnamedRegexInspectionTest : JccInspectionTestBase(UnnamedRegexInspection()) {
8 |
9 |
10 | private fun generic(s: String) = warningAnnot(s, UnnamedRegexInspection.GenericProblemDesc)
11 | private fun reference(s: String) = warningAnnot(s, UnnamedRegexInspection.FreeStandingReferenceProblemDesc)
12 |
13 | fun testLiteralString() = checkByText(
14 | """< "foo" >""".inExpansionCtx()
15 | )
16 |
17 | fun testAll() = checkByText(
18 | """
19 | $DummyHeader
20 |
21 | TOKEN: {
22 | < FOO: "foo" >
23 | | ${generic("< \" Foo \" >")}
24 | | ${reference("< FOO >")}
25 | }
26 |
27 | void Foo() :{}{
28 | < > < "foobar" >
29 | }
30 |
31 | """.trimIndent()
32 | )
33 |
34 | fun testParen() = checkByText(
35 | generic("""< ("foo") >""").inExpansionCtx()
36 | )
37 |
38 |
39 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/intentions/ReplaceOptionValueIntention.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.intentions
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.JccOptionValue
4 | import com.github.oowekyala.ijcc.lang.psi.impl.jccEltFactory
5 | import com.intellij.openapi.editor.Editor
6 | import com.intellij.openapi.project.Project
7 | import com.intellij.psi.PsiDocumentManager
8 |
9 | /**
10 | * @author Clément Fournier
11 | */
12 | class ReplaceOptionValueIntention(private val replacement: String) :
13 | JccSelfTargetingEditorIntentionBase(
14 | JccOptionValue::class.java,
15 | "Replace value with $replacement"
16 | ) {
17 |
18 | override fun isApplicableTo(element: JccOptionValue): Boolean = true
19 |
20 | override fun run(project: Project, editor: Editor, element: JccOptionValue): () -> Unit {
21 |
22 | val elt = project.jccEltFactory.createOptionValue(replacement)
23 |
24 | return {
25 | element.replace(elt)
26 | PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
27 | }
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/lang/JccNodeExtensionsTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang
2 |
3 | import com.github.oowekyala.ijcc.lang.model.RegexKind
4 | import com.github.oowekyala.ijcc.lang.psi.JccContainerRegularExpression
5 | import com.github.oowekyala.ijcc.lang.psi.impl.jccEltFactory
6 | import com.github.oowekyala.ijcc.lang.psi.isPrivate
7 | import com.github.oowekyala.ijcc.lang.psi.isUnclosed
8 | import io.kotest.matchers.shouldBe
9 | import org.junit.Test
10 |
11 | /**
12 | * @author Clément Fournier
13 | * @since 1.0
14 | */
15 | class JccNodeExtensionsTest : ParserTestDsl() {
16 |
17 |
18 | fun `test JccRegexSpec isPrivate`() {
19 |
20 | val spec = project.jccEltFactory.createRegexSpec(RegexKind.TOKEN, "<#FOO: \"f\" >")
21 |
22 | spec.isPrivate shouldBe true
23 |
24 | }
25 |
26 | fun `test unclosed container regex`() {
27 |
28 | "<".asRegex().isUnclosed shouldBe true
29 | "<\"f\"".asRegex().isUnclosed shouldBe true
30 | "<\"f\">".asRegex().isUnclosed shouldBe false
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/icons/bnfProdAndNode.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/highlight/InjectedJavaHighlightVisitor.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.highlight
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.JccPsiElement
4 | import com.github.oowekyala.ijcc.settings.InjectionSupportLevel
5 | import com.github.oowekyala.ijcc.settings.pluginSettings
6 | import com.intellij.codeInsight.daemon.impl.analysis.HighlightVisitorImpl
7 | import com.intellij.lang.injection.InjectedLanguageManager
8 | import com.intellij.psi.PsiFile
9 |
10 | /**
11 | * Highlighter for java code fragments.
12 | *
13 | * @author Clément Fournier
14 | * @since 1.0
15 | */
16 | class InjectedJavaHighlightVisitor : HighlightVisitorImpl() {
17 |
18 | override fun suitableForFile(file: PsiFile): Boolean =
19 | InjectedLanguageManager.getInstance(file.project).let { manager ->
20 | manager.isInjectedFragment(file) && manager.getInjectionHost(file).let { host ->
21 | host is JccPsiElement && host.pluginSettings.injectionSupportLevel == InjectionSupportLevel.FULL
22 | }
23 | }
24 |
25 | override fun clone(): HighlightVisitorImpl =
26 | InjectedJavaHighlightVisitor()
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/settings/JavaccProjectSettingsConfigurable.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.settings
2 |
3 | import com.intellij.openapi.options.Configurable
4 | import com.intellij.openapi.project.Project
5 | import com.intellij.openapi.util.Disposer
6 | import javax.swing.JComponent
7 |
8 | /**
9 | * Manages the plugin settings page.
10 | *
11 | * @author Clément Fournier
12 | * @since 1.0
13 | */
14 | class JavaccProjectSettingsConfigurable(project: Project) : Configurable, Configurable.NoScroll {
15 |
16 |
17 | private val javaccSettings = project.javaccSettings
18 |
19 | private val panelCache: PluginSettingsPage by lazy {
20 | PluginSettingsPage(
21 | javaccSettings.myState
22 | )
23 | }
24 |
25 | override fun isModified(): Boolean = panelCache.toState() != javaccSettings.myState
26 |
27 | override fun getDisplayName(): String = "JavaCC"
28 |
29 | override fun apply() {
30 | javaccSettings.myState = panelCache.toState()
31 | }
32 |
33 | override fun disposeUIResources() = Disposer.dispose(panelCache)
34 |
35 | override fun createComponent(): JComponent? = panelCache.mainPanel
36 |
37 | }
--------------------------------------------------------------------------------
/src/main/resources/com/github/oowekyala/ijcc/optionDescriptions/STATIC.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | JavaCC
4 |
5 | If true, all methods and class variables are specified as static in the
6 | generated parser and token manager. This allows only one parser
7 | object to be present, but it improves the performance of the
8 | parser. To perform multiple parses during one run of your Java
9 | program, you will have to call the ReInit() method to reinitialize
10 | your parser if it is static. If the parser is non-static, you
11 | may use the "new" operator to construct as many parsers as you
12 | wish. These can all be used simultaneously from different threads.
13 |
14 |
15 |
16 | JJTree
17 |
18 | Generate code for a static parser. The default for this is true.
19 | This must be used consistently with the equivalent JavaCC options.
20 | The value of this option is emitted in the JavaCC source.
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/JavaccLanguage.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc
2 |
3 | import com.intellij.lang.Language
4 |
5 | /**
6 | * JavaCC language. JJTree uses the same language instead of a dialect,
7 | * splitting them would probably cause a lot of duplication atm. There's
8 | * two file types though, [JavaccFileType] and [JjtreeFileType].
9 | *
10 | * @author Clément Fournier
11 | * @since 1.0
12 | */
13 | class JavaccLanguage private constructor() : Language("JavaCC") {
14 |
15 | override fun isCaseSensitive(): Boolean = true
16 |
17 | companion object {
18 | val INSTANCE get() = Language.findInstance(JavaccLanguage::class.java)
19 | fun newInstance() = JavaccLanguage()
20 | val displayName get() = INSTANCE.displayName
21 | }
22 | }
23 |
24 | class CongoccLanguage private constructor() : Language(JavaccLanguage.INSTANCE, "CongoCC") {
25 |
26 | override fun isCaseSensitive(): Boolean = true
27 |
28 | companion object {
29 | val INSTANCE get() = Language.findInstance(CongoccLanguage::class.java)
30 | fun newInstance() = CongoccLanguage()
31 | val displayName get() = INSTANCE.displayName
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/lang/parser/JccParserTests.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.parser
2 |
3 | import com.github.oowekyala.ijcc.JavaccParserDefinition
4 | import com.github.oowekyala.ijcc.lang.ParserTestDataPath
5 | import com.intellij.testFramework.ParsingTestCase
6 |
7 | /**
8 | * @author Clément Fournier
9 | * @since 1.0
10 | */
11 | class JccParserTests : ParsingTestCase("", "jjt", JavaccParserDefinition()) {
12 |
13 | private val checkIt = true
14 |
15 | fun testProductions() = doTest(checkIt)
16 | fun testTokens() = doTest(checkIt)
17 | fun testParentheses() = doTest(checkIt)
18 | fun testLookaheads() = doTest(checkIt)
19 | fun testJavaTypes() = doTest(checkIt)
20 | fun testExpansionFails() = doTest(checkIt)
21 | fun testRegexPrecedence() = doTest(checkIt)
22 | fun testAssignments() = doTest(checkIt)
23 | fun testTokenFail() = doTest(checkIt)
24 | fun testProductionTolerance() = doTest(checkIt)
25 | fun testJjtreeStuff() = doTest(checkIt)
26 | fun testAnnotations() = doTest(checkIt)
27 |
28 | override fun getTestDataPath(): String = ParserTestDataPath
29 |
30 | override fun skipSpaces(): Boolean = true
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/quickdoc/JjtNodeDocMaker.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.quickdoc
2 |
3 | import com.github.oowekyala.ijcc.ide.quickdoc.JccDocUtil.buildQuickDoc
4 | import com.github.oowekyala.ijcc.ide.quickdoc.JccNonTerminalDocMaker.BnfSectionName
5 | import com.github.oowekyala.ijcc.lang.psi.JccScopedExpansionUnit
6 | import com.github.oowekyala.ijcc.lang.psi.nodeIdentifier
7 |
8 | /**
9 | * @author Clément Fournier
10 | * @since 1.0
11 | */
12 | object JjtNodeDocMaker {
13 |
14 | fun makeDoc(scopedUnit: JccScopedExpansionUnit): String? =
15 | scopedUnit.nodeIdentifier?.let { id ->
16 | buildQuickDoc {
17 | buildDefinition {
18 | append("#${id.name}") // use the unprefixed name
19 | }
20 | sections {
21 | buildSection(BnfSectionName, sectionDelim = " ::=") {
22 | scopedUnit.expansionUnit.let {
23 | JccNonTerminalDocMaker.ExpansionMinifierVisitor(this).startOn(it)
24 | }
25 | }
26 | jjtreeSection(scopedUnit)
27 |
28 | }
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/ide/inspections/UnnecessaryParenthesesInspectionTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.inspections
2 |
3 | /**
4 | * @author Clément Fournier
5 | * @since 1.0
6 | */
7 | class UnnecessaryParenthesesInspectionTest : JccInspectionTestBase(JccUnnecessaryParenthesesInspection()) {
8 |
9 |
10 | private fun warnung(s: String) = warningAnnot(s, JccUnnecessaryParenthesesInspection.ProblemDescription)
11 |
12 |
13 | fun testReferenceString() = checkByText(
14 | """
15 | $DummyHeader
16 |
17 | TOKEN: {
18 | < FOO: "foo" >
19 | }
20 |
21 | void Foo() :{}{
22 | ${warnung("( )")}
23 | }
24 |
25 | """.trimIndent()
26 | )
27 |
28 | fun testParen() = checkByText(
29 | """< ("foo") > """.inExpansionCtx()
30 | )
31 |
32 | fun testScoped() = checkByText(
33 | """
34 | $DummyHeader
35 |
36 | TOKEN: {
37 | < #FOO: "foo" >
38 | }
39 |
40 | void Foo():{} {
41 | ( "f" #Foo ) #Bar
42 | }
43 |
44 | """.trimIndent()
45 | )
46 |
47 |
48 |
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/intentions/RemoveNameFromRegexIntention.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.intentions
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.JccNamedRegularExpression
4 | import com.github.oowekyala.ijcc.lang.psi.JccRegexSpec
5 | import com.github.oowekyala.ijcc.lang.psi.promoteToRegex
6 | import com.github.oowekyala.ijcc.lang.psi.safeReplace
7 | import com.intellij.codeInsight.intention.LowPriorityAction
8 | import com.intellij.openapi.editor.Editor
9 | import com.intellij.openapi.project.Project
10 |
11 | /**
12 | * @author Clément Fournier
13 | * @since 1.0
14 | */
15 | class RemoveNameFromRegexIntention
16 | : SelfTargetingOffsetIndependentIntention(
17 | JccNamedRegularExpression::class.java,
18 | "Remove name from regex (may change semantics)"
19 | ), LowPriorityAction {
20 | override fun applyTo(project: Project, editor: Editor?, element: JccNamedRegularExpression) {
21 | element.safeReplace(element.regexElement!!.promoteToRegex())
22 | }
23 |
24 | override fun isApplicableTo(element: JccNamedRegularExpression): Boolean {
25 |
26 |
27 | return element.parent !is JccRegexSpec && element.regexElement != null
28 | }
29 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/model/GrammarNature.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.model
2 |
3 | /**
4 | * Type of preprocessor used by a grammar. JJTree is a superset
5 | * of JavaCC so we can implement both with the exact same PSI.
6 | * The [nature][com.github.oowekyala.ijcc.lang.psi.grammarNature] of
7 | * a file is determined by file extension.
8 | *
9 | * Grammar natures are comparable, their ordering is determined
10 | * by inclusion relation of the languages.
11 | *
12 | * @property displayName The display name, in lower case. JavaCC and JJTree
13 | * should always be capitalized.
14 | *
15 | * @author Clément Fournier
16 | * @since 1.2
17 | */
18 | @Suppress("MemberVisibilityCanBePrivate")
19 | enum class GrammarNature(val displayName: String,
20 | val conventionalExtension: String) {
21 | JAVACC("JavaCC", "jj"),
22 | JJTREE("JJTree", "jjt"),
23 | JJTRICKS("JJTricks", "jjtx"),
24 | J21("JavaCC 21", "javacc"),
25 |
26 | /**
27 | * Special nature in which all features are enabled,
28 | * used in injection. Higher than all features.
29 | */
30 | UNKNOWN("unknown", "");
31 |
32 | val dotAndExtension = ".$conventionalExtension"
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/impl/JccOptionBindingImpl.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi.impl
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.JccIdentifier
4 | import com.github.oowekyala.ijcc.lang.psi.JccOptionBinding
5 | import com.github.oowekyala.ijcc.lang.psi.JccOptionValue
6 | import com.github.oowekyala.ijcc.lang.psi.JccVisitor
7 | import com.intellij.lang.ASTNode
8 | import com.intellij.psi.PsiElementVisitor
9 |
10 | /**
11 | * This impl is needed to make getName() return non-null
12 | */
13 | class JccOptionBindingImpl(node: ASTNode) : JccPsiElementImpl(node), JccOptionBinding {
14 |
15 | override val optionValue: JccOptionValue?
16 | get() = findChildByClass(JccOptionValue::class.java)
17 |
18 |
19 | fun accept(visitor: JccVisitor) {
20 | visitor.visitOptionBinding(this)
21 | }
22 |
23 | override fun accept(visitor: PsiElementVisitor) {
24 | if (visitor is JccVisitor)
25 | accept(visitor)
26 | else
27 | super.accept(visitor)
28 | }
29 |
30 | override fun getNameIdentifier(): JccIdentifier? {
31 | return findChildByClass(JccIdentifier::class.java)
32 | }
33 |
34 | override fun getName(): String = node.firstChildNode.text
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/manipulators/JccLiteralRegexManipulator.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi.manipulators
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.JccLiteralRegexUnit
4 | import com.github.oowekyala.ijcc.lang.psi.impl.jccEltFactory
5 | import com.intellij.openapi.util.TextRange
6 | import com.intellij.psi.AbstractElementManipulator
7 | import com.intellij.util.IncorrectOperationException
8 |
9 | /**
10 | * Manipulator for literal regexes.
11 | *
12 | * @author Clément Fournier
13 | * @since 1.0
14 | */
15 | class JccLiteralRegexManipulator : AbstractElementManipulator() {
16 | @Throws(IncorrectOperationException::class)
17 | override fun handleContentChange(
18 | regex: JccLiteralRegexUnit,
19 | range: TextRange,
20 | newContent: String
21 | ): JccLiteralRegexUnit? {
22 | val oldText = regex.stringLiteral.text
23 | val newText = oldText.substring(0, range.startOffset) + newContent +
24 | oldText.substring(range.endOffset)
25 | return regex.replace(
26 | regex.project.jccEltFactory.createRegexElement(
27 | newText
28 | )
29 | ) as JccLiteralRegexUnit?
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/inspections/JccInspectionsProvider.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.inspections
2 |
3 | import com.intellij.codeInspection.InspectionToolProvider
4 |
5 | /**
6 | * @author Clément Fournier
7 | * @since 1.0
8 | */
9 | class JccInspectionsProvider : InspectionToolProvider {
10 | override fun getInspectionClasses(): Array> = arrayOf(
11 | TokenCanNeverBeMatchedInspection::class.java,
12 | BnfStringCanNeverBeMatchedInspection::class.java,
13 | UnnamedRegexInspection::class.java,
14 | UnnecessaryAngledBracesRegexInspection::class.java,
15 | JccUnnecessaryParenthesesInspection::class.java,
16 | SuspiciousNodeDescriptorExprInspection::class.java,
17 | UnusedProductionInspection::class.java,
18 | UnusedPrivateRegexInspection::class.java,
19 | EmptyParserActionsInspection::class.java,
20 | ConsecutiveParserActionsInspection::class.java,
21 | LookaheadIsNotAtChoicePointInspection::class.java,
22 | ActionWithinLookaheadInspection::class.java,
23 | LeftRecursiveProductionInspection::class.java,
24 | LoopInRegexInspection::class.java,
25 | RegexMayMatchEmptyStringInspection::class.java
26 | )
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/intentions/DeleteExpansionIntention.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.intentions
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.JccBnfProduction
4 | import com.github.oowekyala.ijcc.lang.psi.JccExpansion
5 | import com.intellij.codeInsight.intention.LowPriorityAction
6 | import com.intellij.codeInspection.IntentionWrapper
7 | import com.intellij.codeInspection.LocalQuickFix
8 | import com.intellij.openapi.editor.Editor
9 | import com.intellij.openapi.project.Project
10 | import com.intellij.psi.PsiFile
11 |
12 | /**
13 | * Simply deletes an expansion.
14 | *
15 | * @author Clément Fournier
16 | * @since 1.1
17 | */
18 | class DeleteExpansionIntention(val name: String = "Delete expansion")
19 | : SelfTargetingOffsetIndependentIntention(JccExpansion::class.java, name), LowPriorityAction {
20 |
21 | override fun applyTo(project: Project, editor: Editor?, element: JccExpansion) = element.delete()
22 |
23 | override fun isApplicableTo(element: JccExpansion): Boolean = element.parent !is JccBnfProduction
24 |
25 | companion object {
26 | fun quickFix(name: String = "Delete expansion", file: PsiFile): LocalQuickFix =
27 | IntentionWrapper.wrapToQuickFix(DeleteExpansionIntention(name), file)
28 | }
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/JccJavaNonTerminalProductionHeader.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.github.oowekyala.ijcc.lang.injection.MultilineTextEscaper
4 | import com.github.oowekyala.ijcc.lang.psi.impl.jccEltFactory
5 | import com.intellij.psi.LiteralTextEscaper
6 | import com.intellij.psi.PsiLanguageInjectionHost
7 |
8 | /**
9 | * Header of a non-terminal production, containing the java parts.
10 | */
11 | interface JccJavaNonTerminalProductionHeader : JccIdentifierOwner, PsiLanguageInjectionHost {
12 |
13 | val javaFormalParameterList: List
14 |
15 | val javaReturnType: JccJavaReturnType
16 |
17 | val javaThrowsList: JccJavaThrowsList?
18 |
19 | val javaAccessModifier: JccJavaAccessModifier
20 |
21 | override fun getNameIdentifier(): JccIdentifier
22 |
23 | fun toJavaMethodHeader(): String = text
24 |
25 | override fun isValidHost(): Boolean = false
26 |
27 | override fun createLiteralTextEscaper(): LiteralTextEscaper =
28 | MultilineTextEscaper(this)
29 |
30 | override fun updateText(text: String): PsiLanguageInjectionHost =
31 | this.replace(project.jccEltFactory.createJavaNonterminalHeader(text)) as PsiLanguageInjectionHost
32 |
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/intentions/JccSelfTargetingEditorIntentionBase.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.intentions
2 |
3 | import com.intellij.codeInsight.FileModificationService
4 | import com.intellij.openapi.application.ApplicationManager
5 | import com.intellij.openapi.editor.Editor
6 | import com.intellij.openapi.project.Project
7 | import com.intellij.psi.PsiElement
8 |
9 | /**
10 | * A [SelfTargetingOffsetIndependentIntention] that needs an editor to run.
11 | */
12 | abstract class JccSelfTargetingEditorIntentionBase(
13 | target: Class,
14 | name: String
15 | ) : SelfTargetingOffsetIndependentIntention(target, name) {
16 |
17 |
18 | final override fun applyTo(project: Project, editor: Editor?, element: T) {
19 | if (editor == null) throw IllegalArgumentException("This intention requires an editor")
20 |
21 | val kRunnable = run(project, editor, element)
22 |
23 | FileModificationService.getInstance().prepareFileForWrite(element.containingFile)
24 | if (startInWriteAction()) {
25 | kRunnable()
26 | } else {
27 | ApplicationManager.getApplication().runWriteAction(kRunnable)
28 | }
29 | }
30 |
31 |
32 | protected abstract fun run(project: Project, editor: Editor, element: T): () -> Unit
33 |
34 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/gutter/JccProductionToParserLineMarkerProvider.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.gutter
2 |
3 | import com.github.oowekyala.ijcc.icons.JccIcons
4 | import com.github.oowekyala.ijcc.lang.psi.JccNonTerminalProduction
5 | import com.github.oowekyala.ijcc.lang.psi.parserMethod
6 | import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo
7 | import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder
8 | import com.intellij.psi.PsiElement
9 |
10 | /**
11 | * @author Clément Fournier
12 | * @since 1.3
13 | */
14 | class JccProductionToParserLineMarkerProvider
15 | : BaseTargetingLineMarkerProvider(JccNonTerminalProduction::class.java) {
16 |
17 | override fun processElt(elt: JccNonTerminalProduction): Sequence> {
18 |
19 | val target = elt.parserMethod ?: return emptySequence()
20 |
21 | return NavigationGutterIconBuilder.create(JccIcons.GUTTER_PARSER_METHOD)
22 | .setTarget(target)
23 | .setTooltipText("Navigate to parser method in ${target.containingClass?.name}")
24 | .setPopupTitle("Parser class ${target.containingClass?.name}")
25 | .createLineMarkerInfo(elt.nameIdentifier.leaf)
26 | .let { sequenceOf(it) }
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/lang/TestUtil.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang
2 |
3 | import io.kotest.matchers.types.shouldBeInstanceOf
4 | import io.kotest.matchers.shouldBe
5 |
6 |
7 | const val TestResourcesPath = "src/test/resources/"
8 | const val PackagePath = "com/github/oowekyala/ijcc/"
9 |
10 | private const val Fixtures = "fixtures"
11 | const val FoldingTestDataPath = "$TestResourcesPath${PackagePath}lang/folding/$Fixtures"
12 | const val OptionsTestDataPath = "$TestResourcesPath${PackagePath}lang/options/$Fixtures"
13 | const val InjectionTestDataPath = "$TestResourcesPath${PackagePath}lang/injection/$Fixtures"
14 | const val ParserTestDataPath = "$TestResourcesPath${PackagePath}lang/parser/$Fixtures"
15 |
16 |
17 | inline fun Any?.shouldBeA(t: (T) -> Unit) {
18 | this.shouldBeInstanceOf()
19 | t(this as T)
20 | }
21 |
22 | fun Collection.shouldContainOneSuch(t: (T) -> Unit) {
23 | this.any {
24 | try {
25 | t(it)
26 | true
27 | } catch (ass: AssertionError) {
28 | false
29 | }
30 | } shouldBe true
31 | }
32 |
33 | //fun KClass<*>.dataPath(vararg addSegments: String) =
34 | // this.java.`package`.name
35 | // .replace('.', '/')
36 | // .let { "$it/${addSegments.joinToString(separator = "/")}" }
37 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/ide/refs/ReferenceTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.refs
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.JjtNodeClassOwner
4 | import com.github.oowekyala.ijcc.lang.psi.descendantSequence
5 | import com.github.oowekyala.ijcc.lang.psi.typedReference
6 | import com.github.oowekyala.ijcc.lang.util.JccTestBase
7 | import io.kotest.matchers.collections.haveSize
8 | import io.kotest.matchers.should
9 |
10 | /**
11 | * @author Clément Fournier
12 | * @since 1.0
13 | */
14 | class ReferenceTest : JccTestBase() {
15 |
16 | fun testJjtreePolyRef() {
17 |
18 | val file = """
19 |
20 | $DummyHeader
21 |
22 | void Four():{}
23 | {
24 | "4"
25 | }
26 |
27 | void Foo():{}
28 | {
29 | Hello() "4" #Four
30 | }
31 |
32 | void Hello():{}
33 | {
34 | "4" #Four
35 | }
36 |
37 |
38 |
39 | void MyFour() #Four:{}
40 | {
41 | "4"
42 | }
43 |
44 | """.trimIndent().asJccFile()
45 |
46 |
47 | val owner = file.descendantSequence().filterIsInstance().first()
48 |
49 | owner.typedReference!!.multiResolve(false).toList() should haveSize(4)
50 | }
51 |
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build & verify
2 |
3 | on:
4 | push:
5 |
6 | jobs:
7 | build:
8 | name: Build plugin, verify compatiblity against declared minimum support version of intellij.
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: Check out repository
12 | uses: actions/checkout@v2
13 |
14 | - name: Setup Java 11
15 | uses: actions/setup-java@v2
16 | with:
17 | distribution: zulu
18 | java-version: 11
19 |
20 |
21 | - name: Build the plugin using Gradle
22 | uses: eskatos/gradle-command-action@v1
23 | with:
24 | arguments: buildPlugin
25 | wrapper-cache-enabled: true
26 | dependencies-cache-enabled: true
27 | configuration-cache-enabled: true
28 |
29 | - name: Verify Plugin on IntelliJ Platforms
30 | id: verify
31 | uses: ChrisCarini/intellij-platform-plugin-verifier-action@latest
32 | with:
33 | ide-versions: |
34 | ideaIC:2021.1
35 | ideaIU:2021.1
36 | ideaIC:LATEST-EAP-SNAPSHOT
37 |
38 | - name: Get log file path and print contents
39 | run: |
40 | echo "The verifier log file [${{steps.verify.outputs.verification-output-log-filename}}] contents : " ;
41 | cat ${{steps.verify.outputs.verification-output-log-filename}}
42 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/impl/JccRegexSpecImpl.kt:
--------------------------------------------------------------------------------
1 | // This is a generated file. Not intended for manual editing.
2 | package com.github.oowekyala.ijcc.lang.psi.impl
3 |
4 | import com.github.oowekyala.ijcc.lang.psi.*
5 | import com.intellij.lang.ASTNode
6 | import com.intellij.psi.PsiElementVisitor
7 |
8 | class JccRegexSpecImpl(node: ASTNode) : JccPsiElementImpl(node), JccRegexSpec {
9 |
10 | fun accept(visitor: JccVisitor) {
11 | visitor.visitRegexSpec(this)
12 | }
13 |
14 | override fun accept(visitor: PsiElementVisitor) {
15 | if (visitor is JccVisitor)
16 | accept(visitor)
17 | else
18 | super.accept(visitor)
19 | }
20 |
21 | override fun getRegularExpression(): JccRegularExpression =
22 | findNotNullChildByClass(JccRegularExpression::class.java)
23 |
24 | override fun getLexicalStateTransition(): JccIdentifier? = findChildByClass(JccIdentifier::class.java)
25 |
26 | override fun getLexicalActions(): JccJavaBlock? = findChildByClass(JccJavaBlock::class.java)
27 |
28 | override fun getJjtreeNodeDescriptor(): JccJjtreeNodeDescriptor? = findChildByClass(JccJjtreeNodeDescriptor::class.java)
29 |
30 | override fun getName(): String? = nameIdentifier?.text
31 |
32 | override fun getNameIdentifier(): JccIdentifier? = (regularExpression as? JccNamedRegularExpression)?.nameIdentifier
33 | }
34 |
--------------------------------------------------------------------------------
/src/test/resources/com/github/oowekyala/ijcc/lang/parser/fixtures/Parentheses.jjt:
--------------------------------------------------------------------------------
1 | PARSER_BEGIN(JJTreeParser)
2 |
3 | package org.javacc.jjtree;
4 | /**
5 | * This is my parser declaration
6 | */
7 | public class JJTreeParser {
8 |
9 | }
10 |
11 | PARSER_END(JJTreeParser)
12 |
13 |
14 |
15 | void parens() :
16 | {}
17 | {
18 |
19 | ("f")+ // necessary
20 | ("f")* // necessary
21 | ("f")? // necessary
22 |
23 | ("f") // unnecessary
24 | (foo()) // unnecessary
25 | (a=foo()) // unnecessary
26 | (a="f") // unnecessary
27 | (a=) // unnecessary
28 | () // unnecessary
29 | (try{""}catch(foo f){}) // unnecessary
30 | (["hello"]) // unnecessary
31 | (("")?) // unnecessary
32 |
33 | LOOKAHEAD( ("foo" | "bar") ) // unnecessary
34 | LOOKAHEAD(1, ("foo" | "bar") ) // unnecessary
35 |
36 |
37 | ("foo" | "bar") "bzaz" // necessary
38 | (("foo" | "bar") | "bzaz") // necessary, unnecessary
39 |
40 | ("foo" "bar") {} // unnecessary
41 | ("foo" "bar") (foo() | "f") // unnecessary, necessary
42 | }
43 |
44 | void foo():{}{ ("") } // unnecessary
45 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/ide/inspections/EmptyParserActionsInspectionTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.inspections
2 |
3 | /**
4 | * @author Clément Fournier
5 | * @since 1.1
6 | */
7 | class EmptyParserActionsInspectionTest : JccInspectionTestBase(EmptyParserActionsInspection()) {
8 |
9 | private fun String.warn() = warningAnnot(this, EmptyParserActionsInspection.ProblemDescription)
10 |
11 |
12 | fun `test warning range`() = checkByText("""
13 | $DummyHeader
14 |
15 |
16 | void Foo():
17 | {}
18 | {
19 | "foo" "bar" ${"{ }".warn()} "flab" {weLiveInASociety();}
20 | }
21 |
22 |
23 | """)
24 |
25 |
26 | fun `test warning not suppressed`() = checkByText("""
27 | $DummyHeader
28 |
29 |
30 | void Foo():
31 | {}
32 | {
33 | "foo" "bar" ${"{ }".warn()}
34 | }
35 |
36 |
37 | """)
38 |
39 |
40 | fun `test warning void`() = checkByText("""
41 | $DummyHeader
42 |
43 |
44 | void Foo() #void:
45 | {}
46 | {
47 | "foo" "bar" {goo();} ${"{ }".warn()}
48 | }
49 |
50 |
51 | """)
52 |
53 | fun `test warning suppressed 2`() = checkByText("""
54 | $DummyHeader
55 |
56 |
57 | void Foo():
58 | {}
59 | {
60 | ("foo" "bar" { jj(); } { }) #A
61 | }
62 |
63 |
64 | """)
65 |
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/JavaccAstFactory.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.intellij.lang.ASTFactory
4 | import com.intellij.lang.DefaultASTFactory
5 | import com.intellij.openapi.application.ApplicationManager
6 | import com.intellij.psi.impl.source.tree.CompositeElement
7 | import com.intellij.psi.impl.source.tree.FileElement
8 | import com.intellij.psi.impl.source.tree.LeafElement
9 | import com.intellij.psi.impl.source.tree.LeafPsiElement
10 | import com.intellij.psi.tree.IElementType
11 | import com.intellij.psi.tree.IFileElementType
12 |
13 | /**
14 | * Extension point.
15 | *
16 | * @author Clément Fournier
17 | * @since 1.0
18 | */
19 | class JavaccAstFactory : ASTFactory() {
20 |
21 | override fun createComposite(type: IElementType): CompositeElement {
22 | return if (type is IFileElementType) {
23 | FileElement(type, null)
24 | } else CompositeElement(type)
25 | }
26 |
27 | override fun createLeaf(type: IElementType, text: CharSequence): LeafElement {
28 | return when {
29 | JccTypesExt.CommentTypeSet.contains(type) -> {
30 | val default = ApplicationManager.getApplication().getService(DefaultASTFactory::class.java)
31 | default.createComment(type, text)
32 | }
33 |
34 | else -> LeafPsiElement(type, text)
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/impl/JccIdentifierImpl.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi.impl
2 |
3 | import com.github.oowekyala.ijcc.ide.refs.JccLexicalStateReference
4 | import com.github.oowekyala.ijcc.lang.JccTypes.JCC_IDENT
5 | import com.github.oowekyala.ijcc.lang.psi.JccIdentifier
6 | import com.github.oowekyala.ijcc.lang.psi.JccVisitor
7 | import com.github.oowekyala.ijcc.lang.psi.isLexicalStateName
8 | import com.intellij.lang.ASTNode
9 | import com.intellij.psi.PsiElement
10 | import com.intellij.psi.PsiElementVisitor
11 | import com.intellij.psi.PsiReference
12 |
13 | class JccIdentifierImpl(node: ASTNode) : JccPsiElementImpl(node), JccIdentifier {
14 |
15 | fun accept(visitor: JccVisitor) {
16 | visitor.visitIdentifier(this)
17 | }
18 |
19 | override val leaf: PsiElement
20 | get() = findNotNullChildByType(JCC_IDENT)
21 |
22 | override fun setName(name: String): PsiElement = replace(project.jccEltFactory.createIdentifier(name))
23 |
24 | override fun getName(): String = text
25 |
26 | override fun getReference(): PsiReference? = when {
27 | isLexicalStateName -> JccLexicalStateReference(this)
28 | else -> null
29 | }
30 |
31 | override fun accept(visitor: PsiElementVisitor) {
32 | if (visitor is JccVisitor) {
33 | accept(visitor)
34 | } else {
35 | super.accept(visitor)
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/lang/psi/JccElementFactoryTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.impl.jccEltFactory
4 | import com.github.oowekyala.ijcc.lang.util.JccTestBase
5 | import org.junit.Test
6 |
7 | /**
8 | * @author Clément Fournier
9 | * @since 1.0
10 | */
11 | class JccElementFactoryTest : JccTestBase() {
12 |
13 | // mostly catches ClassCastExceptions
14 |
15 |
16 | fun testCreateOptionValue() {
17 | //TODO
18 |
19 | }
20 |
21 |
22 | fun testCreateRegexReference() {
23 | project.jccEltFactory.createRegexElement("")
24 | }
25 |
26 |
27 | fun testCreateLiteralRegexUnit() {
28 | project.jccEltFactory.createRegexElement("\"foo\"")
29 | }
30 |
31 |
32 | fun testCreateBnfExpansion() {
33 | // TODO
34 | }
35 |
36 |
37 | fun testCreateIdentifier() {
38 | project.jccEltFactory.createIdentifier("mlady")
39 | }
40 |
41 |
42 |
43 | fun testCreateJavaExpression() {
44 | project.jccEltFactory.createJavaExpression("1+2")
45 | }
46 |
47 |
48 |
49 | fun testCreateJavaBlock() {
50 | project.jccEltFactory.createJavaBlock("{ hey(); }")
51 | }
52 |
53 |
54 |
55 | fun testCreateAssignmentLhs() {
56 | project.jccEltFactory.createAssignmentLhs("foo.bar")
57 | }
58 |
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/manipulators/JccCommenter.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi.manipulators
2 |
3 | import com.github.oowekyala.ijcc.lang.JccTypes
4 | import com.intellij.lang.CodeDocumentationAwareCommenterEx
5 | import com.intellij.psi.PsiComment
6 | import com.intellij.psi.PsiElement
7 | import com.intellij.psi.tree.IElementType
8 |
9 | class JccCommenter : CodeDocumentationAwareCommenterEx {
10 | override fun getLineCommentPrefix(): String? = "//"
11 |
12 | override fun getBlockCommentPrefix(): String? = "/*"
13 |
14 | override fun getBlockCommentSuffix(): String? = "*/"
15 |
16 | override fun getCommentedBlockCommentPrefix(): String? = null
17 |
18 | override fun getCommentedBlockCommentSuffix(): String? = null
19 |
20 | override fun getLineCommentTokenType(): IElementType? = JccTypes.JCC_END_OF_LINE_COMMENT
21 |
22 | override fun getBlockCommentTokenType(): IElementType? = JccTypes.JCC_C_STYLE_COMMENT
23 |
24 | // TODO javadoc:
25 |
26 | override fun getDocumentationCommentTokenType(): IElementType? = null
27 |
28 | override fun getDocumentationCommentPrefix(): String? = "/**"
29 |
30 | override fun getDocumentationCommentLinePrefix(): String? = "*"
31 |
32 | override fun getDocumentationCommentSuffix(): String? = "*/"
33 |
34 | override fun isDocumentationComment(element: PsiComment): Boolean = false
35 |
36 | override fun isDocumentationCommentText(element: PsiElement): Boolean = false
37 | }
38 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/lang/psi/stubs/JccStubTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi.stubs
2 |
3 | import com.github.oowekyala.ijcc.lang.util.JccTestBase
4 | import com.intellij.openapi.application.runWriteAction
5 | import com.intellij.openapi.vfs.VfsUtil
6 | import com.intellij.psi.impl.DebugUtil
7 | import com.intellij.psi.stubs.StubTreeLoader
8 | import org.intellij.lang.annotations.Language
9 |
10 | /**
11 | * @author Clément Fournier
12 | * @since 1.2
13 | */
14 | class JccStubTest : JccTestBase() {
15 |
16 |
17 | fun `test non-terminals are stubbed under the file`() = doTest(
18 | """
19 | $DummyHeader
20 |
21 | void foo() :{}{
22 | "foo" #f
23 | }
24 |
25 | """,
26 | """
27 | PsiFileStubImpl
28 | BNF_PRODUCTION:BnfProductionStubImpl
29 | SCOPED_EXPANSION_UNIT:JccScopedExpansionUnitStub
30 | """.trimIndent()
31 | )
32 |
33 |
34 |
35 | private fun doTest(@Language("JavaCC") code: String, expectedStubText: String) {
36 | val file = configureByText(code)
37 | val vFile = file.virtualFile!!
38 | runWriteAction {
39 | VfsUtil.saveText(vFile, code)
40 | }
41 | val stubTree = StubTreeLoader.getInstance().readFromVFile(project, vFile) ?: error("Stub tree is null")
42 | val stubText = DebugUtil.stubTreeToString(stubTree.root)
43 | assert(expectedStubText.trimIndent() + "\n" == stubText)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/impl/JjtNodeClassOwnerImpl.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi.impl
2 |
3 | import com.github.oowekyala.ijcc.lang.model.GrammarNature
4 | import com.github.oowekyala.ijcc.lang.psi.JjtNodeClassOwner
5 | import com.github.oowekyala.ijcc.lang.psi.nodeIdentifier
6 | import com.github.oowekyala.ijcc.lang.psi.stubs.JjtNodeClassOwnerStub
7 | import com.intellij.lang.ASTNode
8 | import com.intellij.psi.stubs.IStubElementType
9 |
10 | abstract class JjtNodeClassOwnerImpl>
11 | : JccStubBasedPsiElementImpl, JjtNodeClassOwner {
12 |
13 |
14 | constructor(node: ASTNode) : super(node)
15 |
16 | constructor(stub: TStub, stubType: IStubElementType) : super(stub, stubType)
17 |
18 |
19 | override val nodeQualifiedName: String?
20 | get() = stub?.jjtNodeQualifiedName ?: nodeSimpleName?.let {
21 | val packageName = grammarOptions.nodePackage
22 |
23 | if (packageName.isEmpty()) nodeSimpleName
24 | else "$packageName.$it"
25 | }
26 |
27 | override val nodeSimpleName: String?
28 | get() = stub?.jjtNodeQualifiedName?.substringAfterLast('.')
29 | ?: nodeRawName?.let { grammarOptions.nodePrefix + it }
30 |
31 | override val nodeRawName: String?
32 | get() = stub?.jjtNodeRawName ?: nodeIdentifier?.name?.takeIf {
33 | // nothing generates nodes in jj files
34 | containingFile.grammarNature >= GrammarNature.JJTREE
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/TraversalUtil.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.intellij.lang.parser.GeneratedParserUtilBase
4 | import com.intellij.openapi.util.Conditions
5 | import com.intellij.psi.PsiElement
6 | import com.intellij.psi.SyntaxTraverser
7 | import com.intellij.psi.SyntaxTraverser.psiTraverser
8 | import com.intellij.psi.tree.IElementType
9 |
10 | /**
11 | * @author Clément Fournier
12 | * @since 1.0
13 | */
14 |
15 |
16 | fun grammarTraverser(root: PsiElement): SyntaxTraverser =
17 | psiTraverser().withRoot(root)
18 | .forceDisregardTypes(Conditions.equalTo(GeneratedParserUtilBase.DUMMY_BLOCK))
19 | .filter(Conditions.instanceOf(JccPsiElement::class.java))
20 |
21 | fun grammarTraverserNoJava(root: PsiElement): SyntaxTraverser =
22 | grammarTraverser(root)
23 | .forceIgnore {
24 | when (it) {
25 | is JccJavaCompilationUnit, is JccJavaBlock, is JccJavaExpression -> true
26 | else -> false
27 | }
28 | }
29 |
30 | fun grammarTraverserOnlyBnf(root: PsiElement): SyntaxTraverser =
31 | grammarTraverserNoJava(root)
32 | .forceIgnore(Conditions.instanceOf(JccOptionSection::class.java))
33 | .forceIgnore(Conditions.instanceOf(JccRegexProduction::class.java))
34 |
35 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/quickdoc/JccOptionDocMaker.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.quickdoc
2 |
3 | import com.github.oowekyala.ijcc.ide.quickdoc.HtmlUtil.grayed
4 | import com.github.oowekyala.ijcc.ide.quickdoc.JccDocUtil.buildQuickDoc
5 | import com.github.oowekyala.ijcc.lang.model.GenericOption
6 | import com.github.oowekyala.ijcc.lang.model.IGrammarOptions
7 | import com.github.oowekyala.ijcc.lang.model.presentValue
8 | import com.github.oowekyala.ijcc.lang.psi.JccOptionBinding
9 |
10 | /**
11 | * @author Clément Fournier
12 | * @since 1.2
13 | */
14 | object JccOptionDocMaker {
15 |
16 | fun makeDoc(binding: JccOptionBinding?,
17 | ctx: IGrammarOptions,
18 | opt: GenericOption<*>): String = buildQuickDoc {
19 | definition {
20 | "Option ${HtmlUtil.bold(opt.name)} " + grayed("(${opt.supportedNature.displayName})")
21 | }
22 |
23 | sections {
24 | section("Current value") {
25 | val curValue = opt.getValue(binding, ctx).presentValue()
26 | val default = opt.contextualDefaultValue(ctx).presentValue()
27 |
28 | val tail = when {
29 | curValue == default -> "(=default)"
30 | else -> "(default $default)"
31 | }
32 |
33 | "$curValue ${grayed(tail)}"
34 | }
35 | }
36 |
37 | freeHtml {
38 | opt.description ?: HtmlUtil.emph("(no description)")
39 | }
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/ide/inspections/ConsecutiveParserActionsInspectionTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.inspections
2 |
3 | /**
4 | * @author Clément Fournier
5 | * @since 1.1
6 | */
7 | class ConsecutiveParserActionsInspectionTest : JccInspectionTestBase(ConsecutiveParserActionsInspection()) {
8 |
9 | private fun String.warn() = warningAnnot(this, ConsecutiveParserActionsInspection.ProblemDescription)
10 |
11 |
12 | fun `test warning range`() = checkByText("""
13 | $DummyHeader
14 |
15 |
16 | void Foo():
17 | {}
18 | {
19 | "foo" "bar" ${"{foo();} {bar;} {lol.fo();}".warn()} "flab" {weLiveInASociety();}
20 | }
21 |
22 |
23 | """)
24 |
25 | fun `test warning range in node scope`() = checkByText("""
26 | $DummyHeader
27 |
28 |
29 | void Foo():
30 | {}
31 | {
32 | ("foo" "bar" ${"{foo();} {bar;}".warn()} {lol.fo();}) #F "flab" {weLiveInASociety();}
33 | }
34 |
35 |
36 | """)
37 |
38 | fun `test warning range in node scope 2`() = checkByText("""
39 | $DummyHeader
40 |
41 |
42 | void Foo():
43 | {}
44 | {
45 | "foo" "bar" ${"{foo();} {bar;}".warn()} {lol.fo();}
46 | }
47 |
48 |
49 | """)
50 |
51 | fun `test warning range in node scope 3`() = checkByText("""
52 | $DummyHeader
53 |
54 |
55 | void Foo():
56 | {}
57 | {
58 | "foo" "bar" {foo();} {bar;}
59 | }
60 |
61 |
62 | """)
63 |
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/findusages/JjtreeNodeReferenceSearcher.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.findusages
2 |
3 | import com.github.oowekyala.ijcc.ide.refs.JjtNodePolyReference
4 | import com.github.oowekyala.ijcc.lang.psi.*
5 | import com.intellij.openapi.application.QueryExecutorBase
6 | import com.intellij.psi.PsiReference
7 | import com.intellij.psi.search.searches.ReferencesSearch
8 | import com.intellij.util.Processor
9 |
10 | /**
11 | * @author Clément Fournier
12 | * @since 1.1
13 | */
14 | class JjtreeNodeReferenceSearcher : QueryExecutorBase(true) {
15 |
16 | override fun processQuery(queryParameters: ReferencesSearch.SearchParameters,
17 | consumer: Processor) {
18 |
19 | val toSearch = queryParameters.elementToSearch as? JccIdentifier ?: return
20 |
21 | if (!toSearch.isJjtreeNodeIdentifier) return
22 |
23 | val owner = toSearch.firstAncestorOrNull() ?: return
24 |
25 | findReferencesTo(owner, toSearch.name).all {
26 | // "all" stops on the first "false" result
27 | consumer.process(it)
28 | }
29 | }
30 |
31 | private fun findReferencesTo(origin: JjtNodeClassOwner,
32 | rawName: String): Sequence =
33 | origin.containingFile
34 | .getJjtreeDeclsForRawName(rawName)
35 | .asSequence()
36 | .filter { it != origin }
37 | .mapNotNull { it.typedReference }
38 |
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/ide/inspections/JccInspectionSuppressorTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.inspections
2 |
3 | /**
4 | * @author Clément Fournier
5 | * @since 1.0
6 | */
7 | class JccInspectionSuppressorTest : JccInspectionTestBase(LookaheadIsNotAtChoicePointInspection()) {
8 |
9 |
10 | fun testSuppressSingleComment() = checkByText(
11 | """
12 | $DummyHeader
13 |
14 | //noinspection LookaheadIsNotAtChoicePoint
15 | void Foo(): {}
16 | {
17 | LOOKAHEAD(1) "foo" "bar"
18 | }
19 |
20 | """.trimIndent()
21 | )
22 |
23 |
24 | fun testSuppressCStyleComment() = checkByText(
25 | """
26 | $DummyHeader
27 |
28 | /* noinspection LookaheadIsNotAtChoicePoint */
29 | void Foo(): {}
30 | {
31 | LOOKAHEAD(1) "foo" "bar"
32 | }
33 |
34 | """.trimIndent()
35 | )
36 |
37 |
38 | fun testSuppressAllEol() = checkByText(
39 | """
40 | $DummyHeader
41 |
42 | //noinspection ALL
43 | void Foo(): {}
44 | {
45 | LOOKAHEAD(1) "foo" "bar"
46 | }
47 |
48 | """.trimIndent()
49 | )
50 |
51 | fun testSuppressCStyleInlineComment() = checkByText(
52 | """
53 | $DummyHeader
54 |
55 |
56 | void Foo(): {}
57 | {
58 | /* noinspection LookaheadIsNotAtChoicePoint */ LOOKAHEAD(1) "foo" "bar"
59 | }
60 |
61 | """.trimIndent()
62 | )
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/manipulators/JccJavaCompilationUnitManipulator.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi.manipulators
2 |
3 | import com.github.oowekyala.ijcc.lang.JccTypes
4 | import com.github.oowekyala.ijcc.lang.psi.JccJavaCompilationUnit
5 | import com.github.oowekyala.ijcc.lang.psi.impl.jccEltFactory
6 | import com.github.oowekyala.ijcc.lang.psi.isOfType
7 | import com.github.oowekyala.ijcc.lang.psi.siblingSequence
8 | import com.intellij.openapi.util.TextRange
9 | import com.intellij.psi.AbstractElementManipulator
10 |
11 |
12 | /**
13 | * @author Clément Fournier
14 | * @since 1.0
15 | */
16 | class JccJavaCompilationUnitManipulator : AbstractElementManipulator() {
17 |
18 |
19 | override fun getRangeInElement(element: JccJavaCompilationUnit): TextRange {
20 | val braceOffset = element.lastChild.siblingSequence(false).firstOrNull { it.isOfType(JccTypes.JCC_RBRACE) } ?: return super.getRangeInElement(element)
21 | return TextRange.from(0, braceOffset.textRange.startOffset - element.textRange.startOffset)
22 | }
23 |
24 |
25 | override fun handleContentChange(element: JccJavaCompilationUnit,
26 | range: TextRange,
27 | newContent: String?): JccJavaCompilationUnit? {
28 | val oldText = element.text
29 | val newText = oldText.substring(0, range.startOffset) + newContent +
30 | oldText.substring(range.endOffset)
31 | return element.replace(element.project.jccEltFactory.createJcu(newText)) as JccJavaCompilationUnit
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/folding/JccFoldingOptionsProvider.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.folding
2 |
3 | import com.github.oowekyala.ijcc.settings.JccGlobalSettingsState
4 | import com.github.oowekyala.ijcc.settings.globalPluginSettings
5 | import com.intellij.application.options.editor.CodeFoldingOptionsProvider
6 | import com.intellij.openapi.options.BeanConfigurable
7 | import kotlin.reflect.KMutableProperty
8 |
9 | /**
10 | * @author Clément Fournier
11 | */
12 | class JccFoldingOptionsProvider :
13 | BeanConfigurable(globalPluginSettings, "JavaCC"), CodeFoldingOptionsProvider {
14 |
15 | init {
16 | val settings = globalPluginSettings
17 |
18 | fun checkBox(title: String, prop: KMutableProperty) =
19 | checkBox(title, { prop.getter.call() }, { prop.setter.call(it) })
20 |
21 | checkBox("Java fragments in JavaCC code", settings::isFoldJavaFragments)
22 | checkBox("JavaCC local lookahead declarations", settings::isFoldLookaheads)
23 | checkBox("JavaCC token references that can be replaced by a string literal", settings::isFoldTokenRefs)
24 | checkBox("JavaCC options section", settings::isFoldOptions)
25 | checkBox("JavaCC parser declaration section", settings::isFoldParserDecl)
26 | checkBox("JavaCC token manager declaration section", settings::isFoldTokenMgrDecl)
27 | checkBox("JavaCC regular expression productions (token declarations)", settings::isFoldTokenProds)
28 | checkBox("Generated sections in .jj files (@bgen ... @egen)", settings::isFoldBgenSections)
29 |
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/settings/InjectionSupportLevel.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.settings
2 |
3 | import com.github.oowekyala.ijcc.ide.highlight.InjectedJavaHighlightVisitor
4 | import com.github.oowekyala.ijcc.lang.injection.JavaccLanguageInjector
5 | import org.intellij.lang.annotations.Language
6 |
7 | /**
8 | * Level of Java injection the plugin performs.
9 | *
10 | * @author Clément Fournier
11 | * @since 1.0
12 | */
13 | enum class InjectionSupportLevel(val displayName: String, val description: String) {
14 |
15 | /** No injection. */
16 | DISABLED("Disabled", "No injection"),
17 |
18 | // TODO maybe have a level with a basic, fast injection scheme with no control flow reconstruction
19 | // if performance is still too bad for some users
20 |
21 | /** Enables [JavaccLanguageInjector]*/
22 | @Language("HTML")
23 | CONSERVATIVE(
24 | "Partial",
25 | """
26 | Basic highlighting, code completion, quick documentation,
27 | usage resolution, control-flow analysis, inspections, etc.
28 | This level is already extremely potent, but compilation errors
29 | are not flagged .
30 | """.trimIndent()
31 | ),
32 |
33 | /** Enables [InjectedJavaHighlightVisitor]. */
34 | @Language("HTML")
35 | FULL(
36 | "Full",
37 | """
38 | Adds compilation error checking, including type checking —
39 | everything is like a regular Java file . Be aware that highlighting
40 | updates are most of the time quite slow.
41 | """.trimIndent()
42 | )
43 | }
44 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/ide/inspections/LoopInRegexInspectionTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.inspections
2 |
3 | import com.github.oowekyala.ijcc.ide.inspections.LoopInRegexInspection.Companion.makeMessageImpl
4 |
5 | /**
6 | * @author Clément Fournier
7 | * @since 1.1
8 | */
9 | class LoopInRegexInspectionTest : JccInspectionTestBase(LoopInRegexInspection()) {
10 |
11 |
12 | private fun String.warning(vararg path: String) =
13 | errorAnnot(trimIndent(), makeMessageImpl(path.toList()))
14 |
15 |
16 | fun testSelfRecursion() = checkByText(
17 | """
18 | $DummyHeader
19 |
20 | TOKEN: {
21 | ${">".warning("FOO", "FOO")}
22 | }
23 | """
24 | )
25 |
26 | fun testMutualRecursion() = checkByText(
27 | """
28 | $DummyHeader
29 | TOKEN:{
30 | ${">".warning("FOO", "BAR", "FOO")}
31 | | >
32 | }
33 | """
34 | )
35 |
36 | fun testIndirectRecursion() = checkByText(
37 | """
38 | $DummyHeader
39 | TOKEN:{
40 | ${">".warning("FOO", "BAR", "BAZ", "FOO")}
41 | | >
42 | | >
43 | }
44 |
45 | """
46 | )
47 |
48 | fun testLoopAtAnyPos() = checkByText(
49 | """
50 | $DummyHeader
51 | TOKEN:{
52 | ${">".warning("FOO", "BAR", "BAZ", "FOO")}
53 | | >
54 | | >
55 | }
56 |
57 | """
58 | )
59 |
60 |
61 | }
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/ide/inspections/RegexMayMatchEmptyStringInspectionTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.inspections
2 |
3 | import com.github.oowekyala.ijcc.ide.inspections.RegexMayMatchEmptyStringInspection.Companion.makeMessage
4 | import com.github.oowekyala.ijcc.lang.model.LexicalState
5 |
6 | /**
7 | * @author Clément Fournier
8 | * @since 1.1
9 | */
10 | class RegexMayMatchEmptyStringInspectionTest : JccInspectionTestBase(RegexMayMatchEmptyStringInspection()) {
11 |
12 | private fun String.warning(name: String? = "FOO",
13 | states: List = LexicalState.JustDefaultState) =
14 | warningAnnot(trimIndent(), makeMessage(name, states))
15 |
16 |
17 | fun testEasyNoName() = checkByText(
18 | """
19 | $DummyHeader
20 |
21 | TOKEN: {
22 | ${"\"\"".warning(null)}
23 | }
24 | """
25 | )
26 |
27 |
28 | fun testEasyWithName() = checkByText(
29 | """
30 | $DummyHeader
31 |
32 | TOKEN: {
33 |
34 | }
35 | """
36 | )
37 |
38 | fun testWithAlternative() = checkByText(
39 | """
40 | $DummyHeader
41 |
42 | TOKEN: {
43 |
44 | }
45 | """
46 | )
47 |
48 |
49 | fun testWithRef() = checkByText(
50 | """
51 | $DummyHeader
52 | TOKEN:{
53 | )?".warning()}>
54 | | >
55 | |
56 | }
57 |
58 | """
59 | )
60 |
61 |
62 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/JavaccFileType.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc
2 |
3 | import com.github.oowekyala.ijcc.icons.JccCoreIcons
4 | import com.intellij.openapi.fileTypes.LanguageFileType
5 | import javax.swing.Icon
6 |
7 | private val JavaccLang = JavaccLanguage.newInstance()
8 |
9 | abstract class BaseJccFileType : LanguageFileType(JavaccLang) {
10 | override fun getDisplayName(): String = description
11 | }
12 |
13 | /**
14 | * @since inception
15 | */
16 | class JavaccFileType : BaseJccFileType() {
17 | override fun getIcon(): Icon = JccCoreIcons.JAVACC_FILE
18 |
19 | override fun getName(): String = "JAVACC_GRAMMAR"
20 |
21 | override fun getDefaultExtension(): String = "jj"
22 |
23 | override fun getDescription(): String = "JavaCC grammar"
24 | }
25 |
26 | /**
27 | * This second file type is available for JJTree files.
28 | *
29 | * @since 1.2
30 | */
31 | class JjtreeFileType : BaseJccFileType() {
32 | override fun getIcon(): Icon = JccCoreIcons.JJTREE_FILE
33 |
34 | override fun getName(): String = "JJTREE_GRAMMAR"
35 |
36 | override fun getDefaultExtension(): String = "jjt"
37 |
38 | override fun getDescription(): String = "JJTree grammar"
39 | }
40 |
41 | /**
42 | * This file type is available for Javacc 21.
43 | *
44 | * @since 1.6
45 | */
46 | class Javacc21FileType : LanguageFileType(CongoccLanguage.newInstance()) {
47 | override fun getDisplayName(): String = description
48 | override fun getIcon(): Icon = JccCoreIcons.JAVACC_FILE
49 |
50 | override fun getName(): String = "JAVACC21_GRAMMAR"
51 |
52 | override fun getDefaultExtension(): String = "ccc"
53 |
54 | override fun getDescription(): String = "CongoCC grammar"
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/gutter/JjtreeNodeClassLineMarkerProvider.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.gutter
2 |
3 | import com.github.oowekyala.ijcc.icons.JccIcons
4 | import com.github.oowekyala.ijcc.lang.psi.JccNonTerminalProduction
5 | import com.github.oowekyala.ijcc.lang.psi.JccScopedExpansionUnit
6 | import com.github.oowekyala.ijcc.lang.psi.JjtNodeClassOwner
7 | import com.github.oowekyala.ijcc.lang.psi.nodeClass
8 | import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo
9 | import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder
10 | import com.intellij.psi.PsiElement
11 |
12 | /**
13 | * Adds a gutter icon linking a production to a JJTree node class.
14 | *
15 | * @author Clément Fournier
16 | * @since 1.0
17 | */
18 | class JjtreeNodeClassLineMarkerProvider :
19 | BaseTargetingLineMarkerProvider(JjtNodeClassOwner::class.java) {
20 |
21 | override fun processElt(elt: JjtNodeClassOwner): Sequence> {
22 | val psiClass = elt.nodeClass ?: return emptySequence()
23 |
24 | val builder = NavigationGutterIconBuilder.create(JccIcons.GUTTER_NODE_CLASS).setTarget(psiClass)
25 | .setTooltipText("Navigate to class ${psiClass.name}")
26 | .setPopupTitle("Class ${psiClass.name}")
27 |
28 | val markerBearer = when (elt) {
29 | is JccNonTerminalProduction -> elt.nameIdentifier
30 | is JccScopedExpansionUnit -> elt.jjtreeNodeDescriptor.nameIdentifier
31 | else -> null
32 | }?.leaf
33 |
34 | return markerBearer?.let { builder.createLineMarkerInfo(it) }?.let { sequenceOf(it) } ?: emptySequence()
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/intentions/CheckRegexIntention.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.intentions
2 |
3 | import com.github.oowekyala.ijcc.ide.quickdoc.JccTerminalDocMaker
4 | import com.github.oowekyala.ijcc.lang.psi.JccRefRegularExpression
5 | import com.github.oowekyala.ijcc.lang.psi.JccRegularExpression
6 | import com.github.oowekyala.ijcc.lang.psi.pattern
7 | import com.github.oowekyala.ijcc.util.runIt
8 | import com.intellij.codeInsight.intention.LowPriorityAction
9 | import com.intellij.codeInsight.intention.impl.QuickEditHandler
10 | import com.intellij.openapi.editor.Editor
11 | import com.intellij.openapi.project.Project
12 | import com.intellij.openapi.util.Iconable
13 | import org.intellij.lang.regexp.RegExpLanguage
14 | import javax.swing.Icon
15 |
16 |
17 | class CheckRegExpIntentionAction :
18 | JccSelfTargetingEditorIntentionBase(
19 | JccRegularExpression::class.java,
20 | "Check Regexp"
21 | ),
22 | LowPriorityAction, Iconable {
23 |
24 |
25 | override fun isApplicableTo(element: JccRegularExpression): Boolean =
26 | element !is JccRefRegularExpression && element.pattern != null
27 |
28 | override fun run(project: Project, editor: Editor, element: JccRegularExpression): () -> Unit = {
29 |
30 | element.pattern?.runIt { r ->
31 | val name = JccTerminalDocMaker.htmlNameOfToken(element.name)
32 | val component = CheckTokenRegexForm(r, name, project).rootPanel
33 |
34 | QuickEditHandler.showBalloon(editor, element.containingFile, component)
35 |
36 | }
37 | }
38 |
39 | override fun startInWriteAction(): Boolean = false
40 |
41 | override fun getIcon(flags: Int): Icon? = RegExpLanguage.INSTANCE.associatedFileType?.icon
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/JavaccPairedBraceMatcher.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc
2 |
3 | import com.github.oowekyala.ijcc.lang.JccTypes.*
4 | import com.github.oowekyala.ijcc.lang.psi.JccJavaBlock
5 | import com.github.oowekyala.ijcc.lang.psi.JccNonTerminalProduction
6 | import com.intellij.lang.BracePair
7 | import com.intellij.lang.PairedBraceMatcher
8 | import com.intellij.psi.PsiFile
9 | import com.intellij.psi.tree.IElementType
10 |
11 | /**
12 | * @author Clément Fournier
13 | * @since 1.0
14 | */
15 | class JavaccPairedBraceMatcher : PairedBraceMatcher {
16 | override fun getCodeConstructStart(file: PsiFile?, openingBraceOffset: Int): Int {
17 | val element = file?.findElementAt(openingBraceOffset)
18 | if (element == null || element is PsiFile) return openingBraceOffset
19 |
20 | var parent = element.parent
21 | if (parent is JccJavaBlock) {
22 | parent = parent.getParent()
23 | if (parent is JccNonTerminalProduction) {
24 | return parent.textRange.startOffset
25 | }
26 | } else if (parent is JccNonTerminalProduction) {
27 | return parent.textRange.startOffset
28 | }
29 | return openingBraceOffset
30 | }
31 |
32 |
33 | override fun getPairs(): Array = Companion.pairs
34 |
35 | override fun isPairedBracesAllowedBeforeType(lbraceType: IElementType, contextType: IElementType?): Boolean = true
36 |
37 | companion object {
38 | private val pairs = arrayOf(
39 | BracePair(JCC_LPARENTH, JCC_RPARENTH, true), // TODO structural?
40 | BracePair(JCC_LBRACE, JCC_RBRACE, true),
41 | BracePair(JCC_LBRACKET, JCC_RBRACKET, false),
42 | BracePair(JCC_LT, JCC_GT, false)
43 | )
44 | }
45 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/completion/JccPatterns.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.completion
2 |
3 | import com.github.oowekyala.ijcc.lang.JccTypes
4 | import com.github.oowekyala.ijcc.lang.psi.JccBnfProduction
5 | import com.github.oowekyala.ijcc.lang.psi.JccFile
6 | import com.github.oowekyala.ijcc.lang.psi.JccOptionBinding
7 | import com.intellij.patterns.ElementPattern
8 | import com.intellij.patterns.PlatformPatterns.instanceOf
9 | import com.intellij.patterns.PlatformPatterns.psiElement
10 | import com.intellij.psi.PsiComment
11 | import com.intellij.psi.PsiElement
12 | import com.intellij.psi.TokenType
13 |
14 | /**
15 | * Patterns for auto completion.
16 | *
17 | * TODO we can use those to simplify live template contexts
18 | *
19 | * @author Clément Fournier
20 | * @since 1.2
21 | */
22 | object JccPatterns {
23 |
24 | val placePattern: ElementPattern = psiElement()
25 | .inFile(instanceOf(JccFile::class.java))
26 | .andNot(psiElement().inside(PsiComment::class.java))
27 |
28 | val optionValuePattern: ElementPattern =
29 | psiElement()
30 | .withAncestor(2, psiElement(JccOptionBinding::class.java))
31 | .afterLeafSkipping(psiElement(TokenType.ERROR_ELEMENT), psiElement(JccTypes.JCC_EQ))
32 |
33 | val optionNamePattern: ElementPattern =
34 | psiElement()
35 | .atStartOf(psiElement(JccOptionBinding::class.java))
36 | .andNot(psiElement().inside(PsiComment::class.java))
37 | .andNot(optionValuePattern)
38 |
39 | val bnfColonPattern =
40 | psiElement(JccTypes.JCC_COLON).withParent(JccBnfProduction::class.java)
41 |
42 | val jjtreeHashPattern =
43 | psiElement().afterLeaf(psiElement(JccTypes.JCC_POUND))
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/refs/JccNonTerminalReference.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.refs
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.*
4 | import com.github.oowekyala.ijcc.lang.psi.manipulators.JccIdentifierManipulator
5 | import com.intellij.openapi.util.TextRange
6 | import com.intellij.psi.PsiElement
7 | import com.intellij.psi.PsiReferenceBase
8 |
9 |
10 | /**
11 | * Reference to a [JccNonTerminalProduction].
12 | *
13 | * @author Clément Fournier
14 | * @since 1.0
15 | */
16 | class JccNonTerminalReference(psiElement: JccNonTerminalExpansionUnit) :
17 | PsiReferenceBase(psiElement) {
18 |
19 | override fun resolve(): JccIdentifier? = resolveProduction()?.nameIdentifier
20 |
21 | fun resolveProduction(): JccNonTerminalProduction? {
22 | val searchedName = element.name ?: return null
23 |
24 | return element.containingFile.getProductionByName(searchedName)
25 | }
26 |
27 | override fun isReferenceTo(elt: PsiElement): Boolean {
28 | return when (elt) {
29 | is JccNonTerminalProduction -> elt.name == element.name
30 | is JccIdentifier -> elt.owner?.let { isReferenceTo(it) } == true
31 | else -> false
32 | }
33 | }
34 |
35 |
36 | override fun getVariants(): Array =
37 | JccRefVariantService.getInstance(element.project).nonterminalRefVariants(this)
38 |
39 | override fun calculateDefaultRangeInElement(): TextRange = element.nameIdentifier.textRangeInParent
40 |
41 | override fun handleElementRename(newElementName: String): PsiElement = newElementName.let {
42 | val id = element.nameIdentifier
43 | JccIdentifierManipulator().handleContentChange(id, newElementName)!!
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/stubs/indices/JccParserQnameIndexer.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi.stubs.indices
2 |
3 | import com.github.oowekyala.ijcc.JavaccFileType
4 | import com.github.oowekyala.ijcc.JjtreeFileType
5 | import com.github.oowekyala.ijcc.lang.model.parserQualifiedName
6 | import com.github.oowekyala.ijcc.lang.psi.JccFile
7 | import com.intellij.util.indexing.*
8 | import com.intellij.util.io.EnumeratorStringDescriptor
9 | import com.intellij.util.io.KeyDescriptor
10 |
11 |
12 | /**
13 | * Indexes the qualified name of the parser class of a grammar file,
14 | * in order to provide links from the generated parser to the grammar.
15 | *
16 | * @author Clément Fournier
17 | * @since 1.2
18 | */
19 | class JccParserQnameIndexer : ScalarIndexExtension() {
20 |
21 | override fun getName(): ID = NAME
22 |
23 | override fun getVersion(): Int = 1
24 |
25 | override fun dependsOnFileContent(): Boolean = true // FIXME?
26 |
27 | override fun getIndexer(): DataIndexer = MyDataIndexer
28 |
29 | override fun getInputFilter(): FileBasedIndex.InputFilter =
30 | DefaultFileTypeSpecificInputFilter(JavaccFileType(), JjtreeFileType())
31 |
32 | override fun getKeyDescriptor(): KeyDescriptor = EnumeratorStringDescriptor.INSTANCE
33 |
34 |
35 | private object MyDataIndexer : DataIndexer {
36 | override fun map(inputData: FileContent): Map {
37 |
38 | val file = inputData.psiFile as? JccFile ?: return emptyMap()
39 |
40 | return mapOf(file.grammarOptions.parserQualifiedName to null)
41 | }
42 | }
43 |
44 | companion object {
45 | val NAME = ID.create("jccParserQname")
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/findusages/JccUsageTypeProvider.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.findusages
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.*
4 | import com.intellij.psi.PsiElement
5 | import com.intellij.usages.UsageTarget
6 | import com.intellij.usages.impl.rules.UsageType
7 | import com.intellij.usages.impl.rules.UsageTypeProviderEx
8 |
9 | /**
10 | * @author Clément Fournier
11 | * @since 1.2
12 | */
13 | class JccUsageTypeProvider : UsageTypeProviderEx {
14 |
15 | override fun getUsageType(element: PsiElement, targets: Array): UsageType? = when {
16 | element is JccNonTerminalExpansionUnit -> JccUsageTypes.NONTERMINAL_REFERENCE
17 | element is JccLiteralRegexUnit -> JccUsageTypes.IMPLICIT_STRING_TOKEN_REFERENCE
18 | element is JccTokenReferenceRegexUnit -> JccUsageTypes.EXPLICIT_TOKEN_REFERENCE
19 | element is JccIdentifier && element.isJjtreeNodeIdentifier -> JccUsageTypes.JJTREE_NODE_PARTIAL_DECLARATION
20 | element is JjtNodeClassOwner -> JccUsageTypes.JJTREE_NODE_PARTIAL_DECLARATION
21 | else -> null
22 | }
23 |
24 |
25 | override fun getUsageType(element: PsiElement): UsageType? =
26 | getUsageType(element, UsageTarget.EMPTY_ARRAY)
27 |
28 | object JccUsageTypes {
29 |
30 | val NONTERMINAL_REFERENCE = UsageType { "Non-terminal reference" }
31 | val JJTREE_NODE_PARTIAL_DECLARATION = UsageType { "JJTree node partial declaration" }
32 | val IMPLICIT_STRING_TOKEN_REFERENCE = UsageType { "String token implicit reference" }
33 | val EXPLICIT_TOKEN_REFERENCE = UsageType { "Token explicit reference" }
34 |
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/findusages/JccStringTokenFindUsagesHandlerFactory.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.findusages
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.*
4 | import com.intellij.find.findUsages.FindUsagesHandler
5 | import com.intellij.find.findUsages.FindUsagesHandlerFactory
6 | import com.intellij.psi.PsiElement
7 | import com.intellij.psi.PsiReference
8 | import com.intellij.psi.search.SearchScope
9 |
10 |
11 | class JccStringTokenFindUsagesHandlerFactory : FindUsagesHandlerFactory() {
12 | override fun createFindUsagesHandler(element: PsiElement, forHighlightUsages: Boolean): FindUsagesHandler? =
13 | when (element) {
14 | is JccLiteralRegexUnit ->
15 | element.typedReference!!
16 | .resolveToken(exact = true)
17 | ?.let { JccTokenFindUsagesHandler(it.psiElement!!) }
18 |
19 | is JccIdentifier -> JccTokenFindUsagesHandler(element.namedTokenDef!!)
20 | else -> null
21 | }
22 |
23 | override fun canFindUsages(element: PsiElement): Boolean =
24 | element is JccLiteralRegexUnit && element.typedReference != null
25 | || element is JccIdentifier && element.namedTokenDef != null
26 |
27 | class JccTokenFindUsagesHandler(regexOwner: JccRegularExpressionOwner) : FindUsagesHandler(regexOwner) {
28 |
29 | override fun findReferencesToHighlight(target: PsiElement,
30 | searchScope: SearchScope): MutableCollection {
31 | val realTarget = when (target) {
32 | is JccIdentifier -> target.namedTokenDef!!
33 | else -> target
34 | }
35 |
36 | return super.findReferencesToHighlight(realTarget, searchScope)
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/stubs/indices/JccStubElementTypeHolder.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi.stubs.indices
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.JccBnfProduction
4 | import com.github.oowekyala.ijcc.lang.psi.JccJavacodeProduction
5 | import com.github.oowekyala.ijcc.lang.psi.JccPsiElement
6 | import com.github.oowekyala.ijcc.lang.psi.JccScopedExpansionUnit
7 | import com.github.oowekyala.ijcc.lang.psi.stubs.BnfProductionStubImpl
8 | import com.github.oowekyala.ijcc.lang.psi.stubs.JavacodeProductionStubImpl
9 | import com.github.oowekyala.ijcc.lang.psi.stubs.JccFileStub
10 | import com.github.oowekyala.ijcc.lang.psi.stubs.JccScopedExpansionUnitStub
11 | import com.intellij.psi.stubs.IStubElementType
12 | import com.intellij.psi.stubs.StubElement
13 | import com.intellij.psi.tree.IElementType
14 | import com.intellij.psi.tree.StubFileElementType
15 |
16 | interface JccStubElementTypeHolder {
17 | companion object {
18 | @JvmField
19 | val bnfProd: StubElementType = cast(BnfProductionStubImpl.TYPE)
20 |
21 | @JvmField
22 | val javacodeProd: StubElementType = cast(JavacodeProductionStubImpl.TYPE)
23 |
24 | @JvmField
25 | val unitStub: StubElementType = cast(JccScopedExpansionUnitStub.TYPE)
26 |
27 | @JvmField
28 | val fileStub: StubFileElementType = JccFileStub.TYPE
29 | }
30 | }
31 |
32 |
33 | /** Is needed to avoid very long type names */
34 | private typealias StubElementType = IStubElementType, T>
35 |
36 | @Suppress("UNCHECKED_CAST")
37 | private fun cast(type: IElementType): IStubElementType, T> {
38 | return type as IStubElementType, T>
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/intentions/ReplaceSupersedingUsageWithReferenceIntentionFix.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.intentions
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.JccLiteralRegexUnit
4 | import com.github.oowekyala.ijcc.lang.psi.JccTokenReferenceRegexUnit
5 | import com.github.oowekyala.ijcc.lang.psi.impl.jccEltFactory
6 | import com.github.oowekyala.ijcc.lang.psi.safeReplace
7 | import com.intellij.codeInsight.FileModificationService
8 | import com.intellij.codeInsight.intention.IntentionAction
9 | import com.intellij.openapi.editor.Editor
10 | import com.intellij.openapi.project.Project
11 | import com.intellij.psi.PsiDocumentManager
12 | import com.intellij.psi.PsiFile
13 |
14 | /**
15 | * @author Clément Fournier
16 | * @since 1.2
17 | */
18 | class ReplaceSupersedingUsageWithReferenceIntentionFix(private val toReplace: JccLiteralRegexUnit,
19 | private val tokenName: String) : IntentionAction {
20 | override fun startInWriteAction(): Boolean = true
21 |
22 | override fun getFamilyName(): String = "Replace superseding string with reference to this token"
23 |
24 | override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?): Boolean = true
25 |
26 | override fun getText(): String = familyName
27 |
28 | override fun invoke(project: Project, editor: Editor?, file: PsiFile?) {
29 | if (editor == null) throw IllegalArgumentException("This intention requires an editor")
30 |
31 |
32 | FileModificationService.getInstance().prepareFileForWrite(toReplace.containingFile)
33 | val newRegexUnit: JccTokenReferenceRegexUnit = project.jccEltFactory.createRegexElement("<$tokenName>")
34 |
35 | toReplace.safeReplace(newRegexUnit)
36 | PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
37 |
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/lang/util/TestExtensions.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.util
2 |
3 | import io.kotest.matchers.Matcher
4 | import io.kotest.matchers.MatcherResult
5 | import io.kotest.matchers.shouldNotBe
6 | import io.kotest.matchers.should as ktShould
7 | import io.kotest.matchers.shouldBe as ktShouldBe
8 |
9 |
10 | fun > C?.eachShouldMatchInOrder(vararg assertions: (T) -> Unit) {
11 |
12 | this shouldNotBe null
13 |
14 | this!! // just to inform the type system
15 |
16 |
17 | this.zip(assertions).forEach { (item, matcher) ->
18 | matcher(item)
19 | }
20 | this.size ktShouldBe assertions.size
21 | }
22 |
23 |
24 | fun > C?.eachShouldMatchInOrder(vararg matchers: Matcher) {
25 |
26 | this shouldNotBe null
27 |
28 | this!! // just to inform the type system
29 |
30 | this.size ktShouldBe matchers.size
31 |
32 | this.zip(matchers).forEach { (item, matcher) ->
33 | item ktShould matcher
34 | }
35 | }
36 |
37 | fun String.normalizeWhiteSpace(): String = replace(Regex("""(\s|\R)+"""), " ").trim()
38 |
39 | fun Matcher .map(f: (B) -> A): Matcher = object : Matcher {
40 | override fun test(value: B): MatcherResult = this@map.test(f(value))
41 | }
42 |
43 |
44 | inline fun stringMatchersIgnoreWhitespace(assertions: IgnoreWhitespaceCtx.() -> Unit): Unit =
45 | IgnoreWhitespaceCtx().assertions()
46 |
47 | /** Rebinds match methods for strings to something that normalizes whitespace before handling. */
48 | class IgnoreWhitespaceCtx {
49 |
50 |
51 | infix fun String?.should(matcher: Matcher) {
52 | this?.normalizeWhiteSpace() ktShould matcher.map { it?.normalizeWhiteSpace() }
53 | }
54 |
55 | infix fun String?.shouldBe(value: String?) {
56 | this?.normalizeWhiteSpace() ktShouldBe value?.normalizeWhiteSpace()
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/impl/JccScopedExpansionUnitImpl.kt:
--------------------------------------------------------------------------------
1 | // This is a generated file. Not intended for manual editing.
2 | package com.github.oowekyala.ijcc.lang.psi.impl
3 |
4 | import com.github.oowekyala.ijcc.ide.refs.JjtNodePolyReference
5 | import com.github.oowekyala.ijcc.lang.psi.*
6 | import com.github.oowekyala.ijcc.lang.psi.stubs.JccScopedExpansionUnitStub
7 | import com.intellij.lang.ASTNode
8 | import com.intellij.psi.PsiElementVisitor
9 | import com.intellij.psi.PsiReference
10 | import com.intellij.psi.stubs.IStubElementType
11 | import com.intellij.psi.util.PsiTreeUtil
12 |
13 | class JccScopedExpansionUnitImpl : JjtNodeClassOwnerImpl, JccScopedExpansionUnit {
14 |
15 | override val jjtreeNodeDescriptor: JccJjtreeNodeDescriptor
16 | get() = notNullChild(
17 | PsiTreeUtil.getChildOfType(
18 | this,
19 | JccJjtreeNodeDescriptor::class.java
20 | )
21 | )
22 |
23 | constructor(node: ASTNode) : super(node)
24 |
25 | constructor(stub: JccScopedExpansionUnitStub, stubType: IStubElementType) : super(stub, stubType)
26 |
27 | fun accept(visitor: JccVisitor) {
28 | visitor.visitScopedExpansionUnit(this)
29 | }
30 |
31 | override fun accept(visitor: PsiElementVisitor) {
32 | if (visitor is JccVisitor)
33 | accept(visitor)
34 | else
35 | super.accept(visitor)
36 | }
37 |
38 | override fun getReference(): PsiReference = JjtNodePolyReference(this)
39 |
40 | override val expansionUnit: JccExpansionUnit
41 | get() = notNullChild(PsiTreeUtil.getChildOfType(this, JccExpansionUnit::class.java))
42 |
43 | override fun getNameIdentifier(): JccIdentifier? {
44 | val p1 = jjtreeNodeDescriptor
45 | return p1.nameIdentifier
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/inspections/JccInspectionBase.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.inspections
2 |
3 | import com.github.oowekyala.ijcc.JavaccLanguage
4 | import com.github.oowekyala.ijcc.lang.JccTypes.JCC_C_STYLE_COMMENT
5 | import com.github.oowekyala.ijcc.lang.JccTypes.JCC_END_OF_LINE_COMMENT
6 | import com.github.oowekyala.ijcc.lang.psi.JccTypesExt
7 | import com.github.oowekyala.ijcc.util.contains
8 | import com.intellij.codeInspection.InspectionProfileEntry
9 | import com.intellij.codeInspection.LocalInspectionTool
10 | import com.intellij.psi.PsiElement
11 |
12 | /**
13 | * Base class for inspections.
14 | *
15 | * @author Clément Fournier
16 | * @since 1.0
17 | */
18 | abstract class JccInspectionBase(private val myDisplayName: String) : LocalInspectionTool() {
19 | // Since inspections can be suppressed inspection names and this scheme are published API
20 | // Basically the class name minus the "Inspection" suffix is the id
21 | // If the name collides with inspections of other languages, prefix the node class with "Jcc"
22 | // This is formalized in 1.3
23 | final override fun getID(): String = InspectionProfileEntry.getShortName(this::class.java.simpleName)
24 |
25 | final override fun getDisplayName(): String = myDisplayName
26 | final override fun getShortName(): String = id // short name must be unique wrt all other inspections
27 | final override fun getGroupDisplayName(): String = JavaccLanguage.displayName
28 |
29 | override fun isEnabledByDefault(): Boolean = true
30 | }
31 |
32 | val PsiElement.isJccComment: Boolean
33 | get() = JccTypesExt.CommentTypeSet.contains(this)
34 |
35 | val PsiElement.trimCommentMarkers: String
36 | get() = when (node.elementType) {
37 | JCC_END_OF_LINE_COMMENT -> text.removePrefix("//")
38 | JCC_C_STYLE_COMMENT -> text.removeSurrounding("/*", "*/")
39 | else -> text
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/inspections/ActionWithinLookaheadInspection.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.inspections
2 |
3 | import com.github.oowekyala.ijcc.ide.intentions.DeleteExpansionIntention
4 | import com.github.oowekyala.ijcc.lang.psi.JccLocalLookaheadUnit
5 | import com.github.oowekyala.ijcc.lang.psi.JccParserActionsUnit
6 | import com.github.oowekyala.ijcc.lang.psi.JccVisitor
7 | import com.github.oowekyala.ijcc.lang.psi.ancestors
8 | import com.intellij.codeInspection.ProblemsHolder
9 | import com.intellij.psi.PsiElementVisitor
10 | import org.intellij.lang.annotations.Language
11 |
12 | /**
13 | * @author Clément Fournier
14 | * @since 1.0
15 | */
16 | class ActionWithinLookaheadInspection : JccInspectionBase(DisplayName) {
17 |
18 |
19 | @Language("HTML")
20 | override fun getStaticDescription() = """
21 | Reports parser actions declared inside local lookahead specifications.
22 | Those are ignored during lookahead evaluation.
23 | """.trimIndent()
24 |
25 |
26 | override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor =
27 | object : JccVisitor() {
28 | override fun visitParserActionsUnit(o: JccParserActionsUnit) {
29 |
30 | if (o.ancestors(false).any { it is JccLocalLookaheadUnit }) {
31 | holder.registerProblem(
32 | o,
33 | ProblemDescription,
34 | DeleteExpansionIntention.quickFix(
35 | FixDescription, o.containingFile
36 | )
37 | )
38 | }
39 | }
40 | }
41 |
42 |
43 | companion object {
44 | const val DisplayName = "Parser actions within lookahead specifications are ignored"
45 | const val ProblemDescription = DisplayName
46 | const val FixDescription = "Delete expansion unit"
47 | }
48 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/JjtNodeClassOwner.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | /**
4 | * Node that is tied to a generated node class, assumed to be
5 | * somewhere in the project. This is used to represent the
6 | * partial declarations of JJTree nodes. The methods return
7 | * non-null only if this psi element is associated with a
8 | * node, i.e. we're in a JJTree file and the node is not void.
9 | *
10 | * @author Clément Fournier
11 | * @since 1.0
12 | */
13 | interface JjtNodeClassOwner : JccPsiElement, JccIdentifierOwner {
14 |
15 | // TODO 21 regex specs
16 |
17 | val jjtreeNodeDescriptor: JccJjtreeNodeDescriptor?
18 |
19 | val isVoid: Boolean
20 | get() = nodeRawName == null
21 |
22 |
23 | /** Gets the node's class qualified name. */
24 | val nodeQualifiedName: String?
25 |
26 | /** Gets the node's simple name, accounting for the node prefix, etc. */
27 | val nodeSimpleName: String?
28 |
29 | /** Name without the prefixes. */
30 | val nodeRawName: String?
31 |
32 | }
33 |
34 |
35 | val JjtNodeClassOwner.isNotVoid: Boolean
36 | get() = !isVoid
37 |
38 |
39 |
40 | /**
41 | * Returns the identifier giving its name to the JJTree node.
42 | * It is null if the production or scoped expansion is #void.
43 | * It may differ from [JjtNodeClassOwner.getNameIdentifier] on
44 | * productions that have an annotation renaming them.
45 | */
46 | val JjtNodeClassOwner.nodeIdentifier: JccIdentifier?
47 | get() = when (this) {
48 | is JccScopedExpansionUnit -> jjtreeNodeDescriptor.nameIdentifier
49 | is JccNonTerminalProduction -> jjtreeNodeDescriptor.let {
50 | if (it == null)
51 | if (grammarOptions.isDefaultVoid) null
52 | else this.nameIdentifier
53 | else it.nameIdentifier
54 | }
55 | else -> throw IllegalStateException()
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/findusages/StringReferenceSearcher.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.findusages
2 |
3 | import com.github.oowekyala.ijcc.ide.refs.JccBnfStringLiteralReference
4 | import com.github.oowekyala.ijcc.lang.psi.*
5 | import com.intellij.openapi.application.QueryExecutorBase
6 | import com.intellij.psi.PsiReference
7 | import com.intellij.psi.search.searches.ReferencesSearch
8 | import com.intellij.util.Processor
9 |
10 | /**
11 | * @author Clément Fournier
12 | * @since 1.1
13 | */
14 | class StringReferenceSearcher : QueryExecutorBase(true) {
15 | override fun processQuery(queryParameters: ReferencesSearch.SearchParameters,
16 | consumer: Processor) {
17 |
18 | val toSearch = queryParameters.elementToSearch as? JccRegularExpressionOwner ?: return
19 |
20 | findReferencesTo(toSearch).all {
21 | // "all" stops on the first "false" result
22 | consumer.process(it)
23 | }
24 |
25 | }
26 |
27 | /*
28 | FIXME
29 | this is probably very inefficient, build indices in LexicalGrammar (or stubs!)
30 | we can't use the optimised word scan because it doesn't pick up on non-alphanumeric characters
31 |
32 | */
33 | private fun findReferencesTo(target: JccRegularExpressionOwner): Sequence =
34 | target.containingFile
35 | .allProductions()
36 | .flatMap { it.descendantSequence(includeSelf = true) }
37 | .filterIsInstance()
38 | .mapNotNull { it.regularExpression.asSingleLiteral() }
39 | // filter out declaration
40 | .filter { it != target.definedToken.takeIf { it.isExplicit }?.asStringToken }
41 | .mapNotNull { it.typedReference }
42 | .filter { it.isReferenceTo(target) }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/resources/com/github/oowekyala/ijcc/lang/parser/fixtures/Tokens.jjt:
--------------------------------------------------------------------------------
1 |
2 | PARSER_BEGIN(JJTreeParser)
3 |
4 | PARSER_END(JJTreeParser)
5 |
6 |
7 | SPECIAL_TOKEN :
8 | {
9 | " " | "\t" | "\n" | "\r" | "\f"
10 | }
11 |
12 | SKIP : { <"(:"> { commentNestingDepth = 1; } : COMMENT_STATE }
13 |
14 | // Comments may be nested
15 | < COMMENT_STATE > SKIP : { "(:" { commentNestingDepth++; } }
16 | < COMMENT_STATE > SKIP : { ":)" { SwitchTo(--commentNestingDepth == 0 ? DEFAULT : COMMENT_STATE); } }
17 | < COMMENT_STATE > SKIP : { < ~[] > }
18 |
19 |
20 | TOKEN :
21 | {
22 | // Options is no longer a reserved word (Issue 126)
23 | // < _OPTIONS: "options" >
24 | < _LOOKAHEAD: "LOOKAHEAD" >
25 | | < _IGNORE_CASE: "IGNORE_CASE" >
26 | | < _PARSER_BEGIN: "PARSER_BEGIN" >
27 | | < _PARSER_END: "PARSER_END" >
28 | | < _JAVACODE: "JAVACODE" >
29 | | < _TOKEN: "TOKEN" >
30 | | < _SPECIAL_TOKEN: "SPECIAL_TOKEN" >
31 | | < _MORE: "MORE" >
32 | | < _SKIP: "SKIP" >
33 | | < _TOKEN_MGR_DECLS: "TOKEN_MGR_DECLS" >
34 | | < _EOF: "EOF" >
35 | }
36 |
37 | TOKEN :
38 | {
39 | < LEFT_WILDCARD : "*:" >
40 | | < RIGHT_WILDCARD : ":*" >
41 | |
42 | // The actual lexical grammar for NCName is: any name except * ":" *
43 | < NCNAME: ()* >
44 | |
45 | < EQNAME: (":" )? >
46 | |
47 | < #NAME_START_CHAR_NO_COLON: [
48 | "A"-"Z",
49 | "a"-"z",
50 | "_",
51 | "\u00c0"-"\u00d6",
52 | "\u00d8"-"\u00f6",
53 | "\u00f8"-"\u02ff",
54 | "\u0370"-"\u037d",
55 | "\u037f"-"\u1fff",
56 | "\u200c"-"\u200d",
57 | "\u2070"-"\u218f",
58 | "\u2c00"-"\u2fef",
59 | "\u3001"-"\ud7ff",
60 | "\uf900"-"\ufdcf",
61 | "\ufdf0"-"\ufffd",
62 | "\u1000"-"\uefff"
63 | ] >
64 | |
65 | < #NAME_CHAR_NO_COLON: | [
66 | "-",
67 | ".",
68 | "0"-"9",
69 | "\u00b7",
70 | "\u0300"-"\u036f",
71 | "\u203f"-"\u2040"
72 | ] >
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/gutter/JjtreePartialDeclarationLineMarkerProvider.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.gutter
2 |
3 | import com.github.oowekyala.ijcc.icons.JccIcons
4 | import com.github.oowekyala.ijcc.lang.psi.*
5 | import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo
6 | import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder
7 | import com.intellij.openapi.project.DumbAware
8 | import com.intellij.psi.PsiElement
9 |
10 | /**
11 | * Adds a gutter icon linking a node bearer to its other declarations.
12 | *
13 | * @author Clément Fournier
14 | * @since 1.0
15 | */
16 | class JjtreePartialDeclarationLineMarkerProvider :
17 | BaseTargetingLineMarkerProvider(JjtNodeClassOwner::class.java), DumbAware {
18 |
19 |
20 | override fun processElt(elt: JjtNodeClassOwner): Sequence> =
21 | elt.typedReference
22 | ?.lightMultiResolve()
23 | ?.takeIf { it.size > 1 }
24 | ?.let { targets ->
25 | val nodeName = targets[0].nodeSimpleName!!
26 |
27 | NavigationGutterIconBuilder.create(JccIcons.GUTTER_PARTIAL_DECL)
28 | .setTargets(targets)
29 | .setCellRenderer { JjtPartialDeclCellRenderer }
30 | .setTooltipText("Navigate to partial declarations of $nodeName")
31 | .setPopupTitle("Select partial declaration for $nodeName")
32 | }?.let { builder ->
33 | when (elt) {
34 | is JccNonTerminalProduction -> elt.nameIdentifier
35 | is JccScopedExpansionUnit -> elt.nodeIdentifier
36 | else -> null
37 | }?.leaf?.let {
38 | builder.createLineMarkerInfo(it)
39 | }
40 | }
41 | ?.let { sequenceOf(it) }
42 | .orEmpty()
43 |
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/settings/JavaccAppSettingsService.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.settings
2 |
3 | import com.intellij.openapi.application.ApplicationManager
4 | import com.intellij.openapi.components.PersistentStateComponent
5 | import com.intellij.openapi.components.ServiceManager
6 | import com.intellij.openapi.components.State
7 | import com.intellij.openapi.components.Storage
8 |
9 | /**
10 | * App-level settings of the plugin.
11 | *
12 | * @author Clément Fournier
13 | * @since 1.0
14 | */
15 | @State(name = "JavaccAppSettings", storages = [Storage("javacc-plugin.xml")])
16 | class JavaccAppSettingsService : PersistentStateComponent {
17 |
18 | override fun loadState(state: JccGlobalSettingsState) {
19 | myState = state.copy()
20 | }
21 |
22 | private var myState = JccGlobalSettingsState()
23 |
24 | override fun getState(): JccGlobalSettingsState = myState
25 |
26 | }
27 |
28 | /**
29 | * App-level settings of the plugin.
30 | */
31 | val globalPluginSettings: JccGlobalSettingsState
32 | get() = ApplicationManager.getApplication()
33 | .getService(JavaccAppSettingsService::class.java).state
34 |
35 |
36 | data class JccGlobalSettingsState(
37 | var isFoldJavaFragments: Boolean = true,
38 | var isFoldLookaheads: Boolean = true,
39 | var isFoldTokenRefs: Boolean = true,
40 |
41 | var isFoldOptions: Boolean = true,
42 | var isFoldParserDecl: Boolean = true,
43 | var isFoldTokenMgrDecl: Boolean = true,
44 | var isFoldTokenProds: Boolean = true,
45 |
46 | var isFoldBgenSections: Boolean = true
47 | ) {
48 |
49 | fun setAllFoldingOptsTo(b: Boolean) {
50 | isFoldJavaFragments = b
51 | isFoldLookaheads = b
52 | isFoldTokenRefs = b
53 |
54 | isFoldOptions = b
55 | isFoldParserDecl = b
56 | isFoldTokenMgrDecl = b
57 | isFoldTokenProds = b
58 |
59 | isFoldBgenSections = b
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/quickdoc/JccLexicalStateDocMaker.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.quickdoc
2 |
3 | import com.github.oowekyala.ijcc.ide.quickdoc.HtmlUtil.bold
4 | import com.github.oowekyala.ijcc.ide.quickdoc.HtmlUtil.psiLink
5 | import com.github.oowekyala.ijcc.ide.quickdoc.JccDocUtil.buildQuickDoc
6 | import com.github.oowekyala.ijcc.lang.model.LexicalState
7 | import org.jetbrains.annotations.TestOnly
8 |
9 | /**
10 | * @author Clément Fournier
11 | * @since 1.2
12 | */
13 | object JccLexicalStateDocMaker {
14 |
15 | fun makeDoc(lexicalState: LexicalState): String =
16 | makeDocImpl(
17 | lexicalStateName = lexicalState.name,
18 | successors = lexicalState.successors.map { it.name },
19 | predecessors = lexicalState.predecessors.map { it.name },
20 | numTokens = lexicalState.tokens.size
21 | )
22 |
23 | @TestOnly
24 | fun makeDocImpl(lexicalStateName: String,
25 | successors: List,
26 | predecessors: List,
27 | numTokens: Int) = buildQuickDoc {
28 | definition {
29 | "Lexical state " + bold(lexicalStateName)
30 | }
31 |
32 | sections {
33 | buildSection("Successors") {
34 | successors.joinTo(this) {
35 | psiLink(
36 | linkTextUnescaped = it,
37 | linkTarget = JccDocUtil.linkRefToLexicalState(it)
38 | )
39 | }
40 | }
41 | buildSection("Predecessors") {
42 | predecessors.joinTo(this) {
43 | psiLink(
44 | linkTextUnescaped = it,
45 | linkTarget = JccDocUtil.linkRefToLexicalState(it)
46 | )
47 | }
48 | }
49 |
50 | section("Size in tokens") { numTokens.toString() }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/model/IGrammarOptions.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.model
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.JccFile
4 | import com.github.oowekyala.ijcc.lang.psi.JccOptionBinding
5 |
6 | /**
7 | * Most general options interface.
8 | * Handles JJTricks option files.
9 | */
10 | interface IGrammarOptions {
11 | val nodePackage: String
12 | val isDefaultVoid: Boolean
13 | val nodePrefix: String
14 | val isTrackTokens: Boolean
15 | val nodeTakesParserArg: Boolean
16 | val isUserTokenManager: Boolean
17 |
18 | /**
19 | * If unknown, defaults to the empty string
20 | */
21 | val grammarName: String?
22 |
23 | /**
24 | * Fallback on the options specified in the grammar file.
25 | */
26 | val inlineBindings: InlineGrammarOptions
27 | }
28 |
29 | fun IGrammarOptions.addNodePackage(simpleName: String) =
30 | nodePackage.addPackage(simpleName)
31 |
32 | fun IGrammarOptions.addParserPackage(simpleName: String) =
33 | parserPackage.addPackage(simpleName)
34 |
35 | private fun String.addPackage(toQualify:String)=
36 | if (isEmpty()) toQualify else "$this.$toQualify"
37 |
38 |
39 | val JccFile.allOptionsBindings: List get() = options?.optionBindingList ?: emptyList()
40 |
41 |
42 | val IGrammarOptions.parserQualifiedName: String
43 | get() {
44 | val pack = parserPackage
45 | return if (pack.isEmpty()) parserSimpleName
46 | else "$pack.$parserSimpleName"
47 | }
48 |
49 |
50 | val IGrammarOptions.parserSimpleName: String
51 | get() =
52 | inlineBindings.file.parserDeclaration?.text?.let { classRegex.find(it) }?.groups?.get(1)?.value ?: ""
53 |
54 | private val packageRegex = Regex("\\bpackage\\s+([.\\w]+)")
55 | private val classRegex = Regex("\\bclass\\s+(\\w+)")
56 |
57 | val IGrammarOptions.parserPackage: String
58 | get() = inlineBindings.file.parserDeclaration?.text?.let { packageRegex.find(it) }?.groups?.get(1)?.value ?: ""
59 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/refs/JjtNodePolyReference.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.refs
2 |
3 | import com.github.oowekyala.ijcc.lang.psi.*
4 | import com.github.oowekyala.ijcc.lang.psi.manipulators.JccIdentifierManipulator
5 | import com.intellij.openapi.util.TextRange
6 | import com.intellij.psi.PsiElement
7 | import com.intellij.psi.PsiPolyVariantReferenceBase
8 |
9 |
10 | /**
11 | * Poly reference to the multiple declarations of a JJTree node.
12 | *
13 | * @author Clément Fournier
14 | * @since 1.0
15 | */
16 | class JjtNodePolyReference(psiElement: JjtNodeClassOwner)
17 | : PsiPolyVariantReferenceBase(psiElement) {
18 |
19 | override fun isReferenceTo(otherElt: PsiElement): Boolean =
20 | otherElt is JjtNodeClassOwner
21 | && otherElt.containingFile === element.containingFile
22 | && otherElt.isNotVoid
23 | && otherElt.nodeRawName == element.nodeRawName
24 |
25 | /**
26 | * Like [multiResolve] but doesn't wrap the results in [PsiEltResolveResult]
27 | * and an array. Returned elements always have a name.
28 | */
29 | fun lightMultiResolve(): List =
30 | element.nodeRawName?.let {
31 | element.containingFile.getJjtreeDeclsForRawName(it)
32 | }.orEmpty()
33 |
34 | override fun multiResolve(incompleteCode: Boolean): Array> =
35 | lightMultiResolve()
36 | .map { PsiEltResolveResult(it) }
37 | .toList()
38 | .toTypedArray()
39 |
40 | override fun getRangeInElement(): TextRange = element.nodeIdentifier!!.textRange.relativize(element.textRange)!!
41 |
42 | override fun handleElementRename(newElementName: String): PsiElement =
43 | JccIdentifierManipulator().handleContentChange(element.nodeIdentifier!!, newElementName)!!
44 |
45 | override fun getVariants(): Array =
46 | JccRefVariantService.getInstance(element.project).jjtreeNodeVariants(this)
47 |
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/gutter/JjtNodeToGrammarLineMarkerProvider.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.gutter
2 |
3 | import com.github.oowekyala.ijcc.icons.JccIcons
4 | import com.github.oowekyala.ijcc.lang.model.GrammarNature
5 | import com.github.oowekyala.ijcc.lang.psi.stubs.indices.JjtreeQNameStubIndex
6 | import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo
7 | import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder
8 | import com.intellij.psi.PsiClass
9 | import com.intellij.psi.PsiElement
10 | import com.intellij.psi.search.GlobalSearchScope
11 |
12 | /**
13 | * @author Clément Fournier
14 | * @since 1.2
15 | */
16 | class JjtNodeToGrammarLineMarkerProvider : BaseTargetingLineMarkerProvider(PsiClass::class.java) {
17 | override fun processElt(elt: PsiClass): Sequence> =
18 | elt.qualifiedName
19 | ?.let { qname ->
20 | JjtreeQNameStubIndex.get(qname, elt.project, GlobalSearchScope.allScope(elt.project))
21 | }
22 | ?.takeIf { it.isNotEmpty() }
23 | ?.groupBy { it.containingFile }
24 | ?.mapValues { (grammar, nodes) ->
25 |
26 | if (grammar.grammarNature < GrammarNature.JJTREE) null
27 | else {
28 | elt.nameIdentifier?.let { ident ->
29 | NavigationGutterIconBuilder.create(JccIcons.GUTTER_NAVIGATE_TO_JJTREE_NODE)
30 | .setTargets(nodes)
31 | .setCellRenderer { JjtPartialDeclCellRenderer }
32 | .setTooltipText("Navigate to JJTree node in ${grammar.name}")
33 | .setPopupTitle("Select partial declaration in ${grammar.name}")
34 | .createLineMarkerInfo(ident)
35 | }
36 | }
37 |
38 | }
39 | ?.values
40 | ?.asSequence()
41 | ?.filterNotNull()
42 | .orEmpty()
43 |
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/ide/inspections/UnnecessaryAngledBracesRegexInspectionTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.inspections
2 |
3 | /**
4 | * @author Clément Fournier
5 | * @since 1.0
6 | */
7 | class UnnecessaryAngledBracesRegexInspectionTest : JccInspectionTestBase(UnnecessaryAngledBracesRegexInspection()) {
8 |
9 |
10 | private fun warnung(s: String) = warningAnnot(s, UnnecessaryAngledBracesRegexInspection.ProblemDescription)
11 |
12 | fun testLiteralString() = checkByText(
13 | warnung("""< "foo" >""").inExpansionCtx()
14 | )
15 |
16 | fun testReferenceString() = checkByText(
17 | """
18 | $DummyHeader
19 |
20 | TOKEN: {
21 | < FOO: "foo" >
22 | }
23 |
24 | void Foo() :{}{
25 | ${warnung("< >")}
26 | }
27 |
28 | """.trimIndent()
29 | )
30 |
31 | fun testParen() = checkByText(
32 | """< ("foo") > """.inExpansionCtx()
33 | )
34 |
35 | fun testPrivateReference() = checkByText(
36 | """
37 | $DummyHeader
38 |
39 | TOKEN: {
40 | < #FOO: "foo" >
41 | }
42 |
43 | void Foo():{} {
44 | < >
45 | }
46 |
47 | """.trimIndent()
48 | )
49 |
50 |
51 | fun testUnclosedBraces() = checkByText(
52 | """
53 | $DummyHeader
54 |
55 | TOKEN: {
56 | < #FOO: "foo" >
57 | }
58 |
59 | void Foo():{} {
60 | < "foo"
61 | }
62 |
63 | """.trimIndent()
64 | )
65 |
66 | fun testUnclosedBraces2() = checkByText(
67 | """
68 | $DummyHeader
69 |
70 | TOKEN: {
71 | < #FOO: "foo" >
72 | }
73 |
74 | void Foo():{} {
75 | <
76 | }
77 |
78 | """.trimIndent()
79 | )
80 |
81 |
82 | }
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/oowekyala/ijcc/ide/inspections/UnusedProductionInspectionTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.inspections
2 |
3 | import com.github.oowekyala.ijcc.ide.inspections.UnusedProductionInspection.Companion.ErrorType.UNREACHABLE
4 | import com.github.oowekyala.ijcc.ide.inspections.UnusedProductionInspection.Companion.ErrorType.UNUSED
5 |
6 | /**
7 | * @author Clément Fournier
8 | * @since 1.1
9 | */
10 | class UnusedProductionInspectionTest : JccInspectionTestBase(UnusedProductionInspection()) {
11 |
12 |
13 | private fun unused(name: String) = warningAnnot(name, UNUSED.makeMessage(name))
14 | private fun unreachable(name: String) = warningAnnot(name, UNREACHABLE.makeMessage(name))
15 |
16 |
17 | fun `test unused`() = checkByText(
18 | """
19 | $DummyHeader
20 |
21 | void Foo():
22 | {}
23 | {
24 | "foo"
25 | }
26 |
27 | void ${unused("Unused")}(): {}{
28 | "hello"
29 | }
30 |
31 | """.trimIndent()
32 | )
33 |
34 |
35 | fun `test unreachable`() = checkByText(
36 | """
37 | $DummyHeader
38 |
39 | TOKEN: {
40 | "foo"
41 | }
42 |
43 | void Foo():
44 | {}
45 | {
46 | "foo"
47 | }
48 |
49 | void ${unused("Unused")}(): {}{
50 | "hello" Unreachable()
51 | }
52 |
53 | void ${unreachable("Unreachable")}(): {}{
54 | "bazouli"
55 | }
56 |
57 | """.trimIndent()
58 | )
59 |
60 |
61 | fun `test suppression transitivity`() = checkByText(
62 | """
63 | $DummyHeader
64 |
65 | TOKEN: {
66 | "foo"
67 | }
68 |
69 | void Foo():
70 | {}
71 | {
72 | "foo"
73 | }
74 |
75 | //noinspection UnusedProduction
76 | void Unused(): {}{
77 | "hello" Unreachable()
78 | }
79 |
80 | void Unreachable(): {}{
81 | "bazouli"
82 | }
83 |
84 | """.trimIndent()
85 | )
86 |
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/lang/psi/JccJjtreeNodeDescriptor.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.lang.psi
2 |
3 | import com.github.oowekyala.ijcc.lang.JccTypes
4 | import com.intellij.psi.PsiElement
5 |
6 | /**
7 | * Node descriptor.
8 | *
9 | *
10 | * JjtNodeDescriptor ::= "#" ( [JccIdentifier] | "void" ) [ "(" [JccJjtreeNodeDescriptorExpr] ")" ]
11 | *
12 | * @author Clément Fournier
13 | * @since 1.0
14 | */
15 | interface JccJjtreeNodeDescriptor : JccPsiElement, JccIdentifierOwner {
16 |
17 | /**
18 | * Returns the expression if one was specified.
19 | */
20 | val descriptorExpr: JccJjtreeNodeDescriptorExpr?
21 | get() = lastChildNoWhitespace as JccJjtreeNodeDescriptorExpr?
22 |
23 | /** Is null if this is void. */
24 | override fun getNameIdentifier(): JccIdentifier?
25 |
26 | /** Either the identifier or the void element. */
27 | val namingLeaf: PsiElement
28 | get() = nameIdentifier ?: node.findChildByType(JccTypes.JCC_VOID_KEYWORD)!!.psi
29 |
30 | /**
31 | * Gets the production header of the production to which this
32 | * descriptor is applied. If null then [expansionUnit] won't
33 | * return null, bc this is applied to a single expansion unit.
34 | */
35 | val productionHeader: JccJavaNonTerminalProductionHeader?
36 | get() = parent.let { it as? JccNonTerminalProduction }?.header
37 |
38 | /**
39 | * Gets the expansion unit that is the scope of this node.
40 | * If null then [productionHeader] won't return null, bc this
41 | * is applied to a whole production.
42 | */
43 | val expansionUnit: JccExpansionUnit?
44 | get() = parent.let { it as? JccScopedExpansionUnit }?.expansionUnit
45 |
46 | /**
47 | * Returns true if this is a "#void" annotation.
48 | */
49 | val isVoid: Boolean
50 | get() = nameIdentifier == null
51 |
52 | val isIndefinite: Boolean
53 | get() = descriptorExpr == null
54 |
55 | val isGreaterThan: Boolean
56 | get() = descriptorExpr != null && descriptorExpr!!.isGtExpression
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/inspections/EmptyParserActionsInspection.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.inspections
2 |
3 | import com.github.oowekyala.ijcc.ide.intentions.DeleteExpansionIntention
4 | import com.github.oowekyala.ijcc.lang.cfa.isNextStep
5 | import com.github.oowekyala.ijcc.lang.psi.*
6 | import com.github.oowekyala.ijcc.util.deleteWhitespace
7 | import com.intellij.codeInspection.ProblemsHolder
8 | import com.intellij.psi.PsiElementVisitor
9 | import org.intellij.lang.annotations.Language
10 |
11 | /**
12 | * @author Clément Fournier
13 | * @since 1.0
14 | */
15 | class EmptyParserActionsInspection : JccInspectionBase(DisplayName) {
16 |
17 | @Language("HTML")
18 | override fun getStaticDescription() = """
19 | Reports empty parser actions unit, which are unnecessary and
20 | may cause some JavaCC warnings.
21 | """.trimIndent()
22 |
23 |
24 | override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor =
25 | object : JccVisitor() {
26 | override fun visitParserActionsUnit(o: JccParserActionsUnit) {
27 |
28 | if (o.text.deleteWhitespace() == "{}") {
29 |
30 | val parentScope =
31 | o.ancestors(includeSelf = false)
32 | .filterIsInstance()
33 | .firstOrNull { it.isNotVoid }
34 |
35 | if (parentScope != null && o.isNextStep(parentScope) && o.prevSiblingNoWhitespace is JccParserActionsUnit)
36 | return
37 |
38 | holder.registerProblem(
39 | o,
40 | ProblemDescription,
41 | DeleteExpansionIntention.quickFix(FixDescription, o.containingFile)
42 | )
43 | }
44 | }
45 | }
46 |
47 |
48 | companion object {
49 | const val DisplayName = "Empty parser actions unit"
50 | const val ProblemDescription = "Empty parser actions unit"
51 | const val FixDescription = "Delete expansion unit"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/do-release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Release script for the idea plugin
4 | # Execute it from the root directory
5 |
6 | set -e
7 |
8 |
9 | git checkout main -q
10 |
11 | CHANGELOG_LOCATION="changelog.html"
12 |
13 | function incr_ver_num() {
14 | ret=$(echo "$1" | awk -F. -v OFS=. 'NF==1{print ++$NF}; NF>1{if(length($NF+1)>length($NF))$(NF-1)++; $NF=sprintf("%0*d", length($NF), ($NF+1)%(10^length($NF))); print}')
15 | echo "$ret"
16 | }
17 |
18 | release_version=$(./gradlew properties -q --console=plain | grep "version:" | awk '{print $2}')
19 |
20 | echo "Preparing release for version $release_version, from branch main..."
21 |
22 | read -p "Enter the name of the release tag (default v$release_version): " tagname
23 |
24 | if [[ -z "$tagname" ]]; then
25 | tagname="v$release_version"
26 | fi
27 |
28 | git tag -fa "$tagname" -F "$CHANGELOG_LOCATION"
29 |
30 | release_changelog=$(mktemp)
31 |
32 | cp "$CHANGELOG_LOCATION" "$release_changelog"
33 |
34 | echo "Publishing plugin to repository..."
35 |
36 | ./gradlew publishPlugin
37 |
38 |
39 | echo "Pushing objects..."
40 |
41 | git push origin main
42 | git push --tags
43 |
44 | default_nr=$(incr_ver_num "$release_version")
45 |
46 | read -p "What's the version number of the next release? (default $default_nr)" next_release
47 |
48 | if [[ -z "$next_release" ]]; then
49 | next_release="$default_nr"
50 | fi
51 |
52 | replacement="s/version = \"$release_version\"/version = \"$next_release\"/"
53 |
54 | sed -i -e "$replacement" build.gradle.kts
55 | git add build.gradle.kts
56 |
57 | echo "\nResetting the changelog..."
58 |
59 | read -r -d '' DEFAULT_CHANGELOG <<'EOF'
60 | What's new:
61 |
62 |
65 |
66 | What's changed:
67 |
70 |
71 | What's fixed:
72 |
75 | EOF
76 |
77 | echo "$DEFAULT_CHANGELOG" > "$CHANGELOG_LOCATION"
78 |
79 | git add "$CHANGELOG_LOCATION"
80 | git commit -m "Prepare next development version $next_release"
81 |
82 | echo "\nSuccessfully released $release_version, edit the release notes on Github with the contents of $release_changelog"
83 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/oowekyala/ijcc/ide/refs/JccBnfStringLiteralReference.kt:
--------------------------------------------------------------------------------
1 | package com.github.oowekyala.ijcc.ide.refs
2 |
3 | import com.github.oowekyala.ijcc.lang.model.RegexKind
4 | import com.github.oowekyala.ijcc.lang.model.Token
5 | import com.github.oowekyala.ijcc.lang.psi.JccLiteralRegexUnit
6 | import com.github.oowekyala.ijcc.lang.psi.JccRegexExpansionUnit
7 | import com.github.oowekyala.ijcc.lang.psi.JccRegexSpec
8 | import com.github.oowekyala.ijcc.lang.psi.innerRange
9 | import com.intellij.openapi.util.TextRange
10 | import com.intellij.psi.PsiElement
11 | import com.intellij.psi.PsiReferenceBase
12 |
13 | /**
14 | * Reference from a literal regex written in BNF to its [Token]. Regexes in BNF are always in the
15 | * default state.
16 | *
17 | * If there exists a [JccRegexSpec] in the default state defined as *exactly* this string,
18 | * the reference points to that regex. Otherwise a new string token is synthesized by JavaCC
19 | * (see documentation on [Token]). Then this reference's [resolve] points to the [JccRegexExpansionUnit]
20 | * generating it.
21 | *
22 | * @author Clément Fournier
23 | * @since 1.0
24 | */
25 | class JccBnfStringLiteralReference(element: JccLiteralRegexUnit) :
26 | PsiReferenceBase(element) {
27 |
28 | /**
29 | * Resolves the token that matches this literal. If [exact], only exact
30 | * string literals will be returned (meaning [Token.asStringToken] is non-null).
31 | * Otherwise full regex will be used.
32 | */
33 | fun resolveToken(exact: Boolean): Token? =
34 | element.containingFile
35 | .lexicalGrammar
36 | .defaultState
37 | .matchLiteral(element, exact, RegexKind.All)
38 |
39 | override fun resolve(): PsiElement? = resolveToken(exact = true)?.psiElement
40 |
41 | override fun calculateDefaultRangeInElement(): TextRange = element.innerRange()
42 |
43 | /**
44 | * Enables autocompletion. Only tokens from the default state are considered.
45 | */
46 | override fun getVariants(): Array =
47 | JccRefVariantService.getInstance(element.project).stringLiteralVariants(this)
48 |
49 | }
50 |
--------------------------------------------------------------------------------