From 40f459306a299186b46857647cc36de6560e4f94 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 2 Feb 2015 18:32:13 +0100 Subject: [PATCH] parse qualified names in kdoc --- .../org/jetbrains/kotlin/kdoc/lexer/KDoc.flex | 2 +- .../kotlin/kdoc/lexer/KDocTokens.java | 15 +- .../kotlin/kdoc/lexer/_KDocLexer.java | 174 ++++++++++-------- .../kotlin/kdoc/parser/KDocElementType.java | 10 +- .../kotlin/kdoc/parser/KDocElementTypes.java | 2 + .../kotlin/kdoc/parser/KDocLinkParser.kt | 69 +++++++ .../kotlin/kdoc/parser/KDocParser.java | 2 + .../kotlin/kdoc/psi/impl/KDocName.kt | 27 +++ .../kotlin/parsing/JetParserDefinition.java | 5 + compiler/testData/psi/kdoc/Markdown.txt | 12 +- .../psi/kdoc/MarkdownQualifiedName.kt | 5 + .../psi/kdoc/MarkdownQualifiedName.txt | 48 +++++ compiler/testData/psi/kdoc/ParamTag.txt | 3 +- .../testData/psi/kdoc/ParamTagAtStart.txt | 3 +- .../testData/psi/kdoc/ReturnWithBrackets.txt | 6 +- compiler/testData/psi/kdoc/Sections.txt | 6 +- .../parsing/JetParsingTestGenerated.java | 6 + 17 files changed, 302 insertions(+), 93 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/kdoc/parser/KDocLinkParser.kt create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocName.kt create mode 100644 compiler/testData/psi/kdoc/MarkdownQualifiedName.kt create mode 100644 compiler/testData/psi/kdoc/MarkdownQualifiedName.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/KDoc.flex b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/KDoc.flex index a7e0e5fedda..0b289c916d7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/KDoc.flex +++ b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/KDoc.flex @@ -53,7 +53,7 @@ ALPHA=[:jletter:] TAG_NAME={ALPHA}({ALPHA}|{DIGIT})* IDENTIFIER={ALPHA}({ALPHA}|{DIGIT}|".")* CODE_LINK_START={ALPHA} -CODE_LINK_CHAR={ALPHA}|{DIGIT}|[()\-\.<>] +CODE_LINK_CHAR={ALPHA}|{DIGIT}|[\.] CODE_LINK=\[{CODE_LINK_START}{CODE_LINK_CHAR}*\] %% diff --git a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/KDocTokens.java b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/KDocTokens.java index 250cd27a5f7..df450cd06f7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/KDocTokens.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/KDocTokens.java @@ -26,8 +26,10 @@ import com.intellij.psi.tree.ILazyParseableElementType; import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.idea.JetLanguage; +import org.jetbrains.kotlin.kdoc.parser.KDocLinkParser; import org.jetbrains.kotlin.kdoc.parser.KDocParser; import org.jetbrains.kotlin.kdoc.psi.impl.KDocImpl; +import org.jetbrains.kotlin.lexer.JetLexer; public interface KDocTokens { ILazyParseableElementType KDOC = new ILazyParseableElementType("KDoc", JetLanguage.INSTANCE) { @@ -62,7 +64,18 @@ public interface KDocTokens { */ KDocToken TEXT_OR_LINK = new KDocToken("KDOC_TEXT_OR_LINK"); KDocToken TAG_NAME = new KDocToken("KDOC_TAG_NAME"); - KDocToken MARKDOWN_LINK = new KDocToken("KDOC_MARKDOWN_LINK"); + ILazyParseableElementType MARKDOWN_LINK = new ILazyParseableElementType("KDOC_MARKDOWN_LINK", JetLanguage.INSTANCE) { + @Override + public ASTNode parseContents(ASTNode chameleon) { + PsiElement parentElement = chameleon.getTreeParent().getPsi(); + Project project = parentElement.getProject(); + PsiBuilder builder = PsiBuilderFactory.getInstance().createBuilder(project, chameleon, new JetLexer(), getLanguage(), + chameleon.getText()); + PsiParser parser = new KDocLinkParser(); + + return parser.parse(this, builder).getFirstChildNode(); + } + }; KDocToken MARKDOWN_ESCAPED_CHAR = new KDocToken("KDOC_MARKDOWN_ESCAPED_CHAR"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/_KDocLexer.java b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/_KDocLexer.java index 4c9eaba2c23..cb3240248d6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/_KDocLexer.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/_KDocLexer.java @@ -1,4 +1,20 @@ -/* The following code was generated by JFlex 1.4.3 on 2/2/15 2:35 PM */ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* The following code was generated by JFlex 1.4.3 on 2/3/15 2:37 PM */ package org.jetbrains.kotlin.kdoc.lexer; @@ -12,7 +28,7 @@ import java.lang.Character; /** * This class is a scanner generated by * JFlex 1.4.3 - * on 2/2/15 2:35 PM from the specification file + * on 2/3/15 2:37 PM from the specification file * /Users/yole/jetbrains/kotlin/compiler/frontend/src/org/jetbrains/kotlin/kdoc/lexer/KDoc.flex */ class _KDocLexer implements FlexLexer { @@ -40,67 +56,67 @@ class _KDocLexer implements FlexLexer { * Translates characters to character classes */ private static final String ZZ_CMAP_PACKED = - "\11\0\1\1\1\13\1\0\2\1\22\0\1\1\3\0\1\3\3\0"+ - "\2\5\1\11\2\0\1\5\1\4\1\10\12\2\2\0\1\5\1\0"+ - "\1\5\1\0\1\12\32\3\1\6\1\14\1\7\1\0\1\3\1\0"+ - "\32\3\47\0\4\3\4\0\1\3\12\0\1\3\4\0\1\3\5\0"+ - "\27\3\1\0\37\3\1\0\u013f\3\31\0\162\3\4\0\14\3\16\0"+ - "\5\3\11\0\1\3\213\0\1\3\13\0\1\3\1\0\3\3\1\0"+ - "\1\3\1\0\24\3\1\0\54\3\1\0\46\3\1\0\5\3\4\0"+ - "\202\3\10\0\105\3\1\0\46\3\2\0\2\3\6\0\20\3\41\0"+ - "\46\3\2\0\1\3\7\0\47\3\110\0\33\3\5\0\3\3\56\0"+ - "\32\3\5\0\13\3\43\0\2\3\1\0\143\3\1\0\1\3\17\0"+ - "\2\3\7\0\2\3\12\0\3\3\2\0\1\3\20\0\1\3\1\0"+ - "\36\3\35\0\3\3\60\0\46\3\13\0\1\3\u0152\0\66\3\3\0"+ - "\1\3\22\0\1\3\7\0\12\3\43\0\10\3\2\0\2\3\2\0"+ - "\26\3\1\0\7\3\1\0\1\3\3\0\4\3\3\0\1\3\36\0"+ - "\2\3\1\0\3\3\16\0\4\3\21\0\6\3\4\0\2\3\2\0"+ - "\26\3\1\0\7\3\1\0\2\3\1\0\2\3\1\0\2\3\37\0"+ - "\4\3\1\0\1\3\23\0\3\3\20\0\11\3\1\0\3\3\1\0"+ - "\26\3\1\0\7\3\1\0\2\3\1\0\5\3\3\0\1\3\22\0"+ - "\1\3\17\0\2\3\17\0\1\3\23\0\10\3\2\0\2\3\2\0"+ - "\26\3\1\0\7\3\1\0\2\3\1\0\5\3\3\0\1\3\36\0"+ - "\2\3\1\0\3\3\17\0\1\3\21\0\1\3\1\0\6\3\3\0"+ - "\3\3\1\0\4\3\3\0\2\3\1\0\1\3\1\0\2\3\3\0"+ - "\2\3\3\0\3\3\3\0\10\3\1\0\3\3\77\0\1\3\13\0"+ - "\10\3\1\0\3\3\1\0\27\3\1\0\12\3\1\0\5\3\46\0"+ - "\2\3\43\0\10\3\1\0\3\3\1\0\27\3\1\0\12\3\1\0"+ - "\5\3\3\0\1\3\40\0\1\3\1\0\2\3\43\0\10\3\1\0"+ - "\3\3\1\0\27\3\1\0\20\3\46\0\2\3\43\0\22\3\3\0"+ - "\30\3\1\0\11\3\1\0\1\3\2\0\7\3\72\0\60\3\1\0"+ - "\2\3\13\0\10\3\72\0\2\3\1\0\1\3\2\0\2\3\1\0"+ - "\1\3\2\0\1\3\6\0\4\3\1\0\7\3\1\0\3\3\1\0"+ - "\1\3\1\0\1\3\2\0\2\3\1\0\4\3\1\0\2\3\11\0"+ - "\1\3\2\0\5\3\1\0\1\3\25\0\2\3\42\0\1\3\77\0"+ - "\10\3\1\0\42\3\35\0\4\3\164\0\42\3\1\0\5\3\1\0"+ - "\2\3\45\0\6\3\112\0\46\3\12\0\51\3\7\0\132\3\5\0"+ - "\104\3\5\0\122\3\6\0\7\3\1\0\77\3\1\0\1\3\1\0"+ - "\4\3\2\0\7\3\1\0\1\3\1\0\4\3\2\0\47\3\1\0"+ - "\1\3\1\0\4\3\2\0\37\3\1\0\1\3\1\0\4\3\2\0"+ - "\7\3\1\0\1\3\1\0\4\3\2\0\7\3\1\0\7\3\1\0"+ - "\27\3\1\0\37\3\1\0\1\3\1\0\4\3\2\0\7\3\1\0"+ - "\47\3\1\0\23\3\105\0\125\3\14\0\u026c\3\2\0\10\3\12\0"+ - "\32\3\5\0\113\3\3\0\3\3\17\0\15\3\1\0\4\3\16\0"+ - "\22\3\16\0\22\3\16\0\15\3\1\0\3\3\17\0\64\3\43\0"+ - "\1\3\3\0\2\3\103\0\130\3\10\0\51\3\127\0\35\3\63\0"+ - "\36\3\2\0\5\3\u038b\0\154\3\224\0\234\3\4\0\132\3\6\0"+ - "\26\3\2\0\6\3\2\0\46\3\2\0\6\3\2\0\10\3\1\0"+ - "\1\3\1\0\1\3\1\0\1\3\1\0\37\3\2\0\65\3\1\0"+ - "\7\3\1\0\1\3\3\0\3\3\1\0\7\3\3\0\4\3\2\0"+ - "\6\3\4\0\15\3\5\0\3\3\1\0\7\3\102\0\2\3\23\0"+ - "\1\3\34\0\1\3\15\0\1\3\40\0\22\3\120\0\1\3\4\0"+ - "\1\3\2\0\12\3\1\0\1\3\3\0\5\3\6\0\1\3\1\0"+ - "\1\3\1\0\1\3\1\0\4\3\1\0\3\3\1\0\7\3\3\0"+ - "\3\3\5\0\5\3\26\0\44\3\u0e81\0\3\3\31\0\11\3\7\0"+ - "\5\3\2\0\5\3\4\0\126\3\6\0\3\3\1\0\137\3\5\0"+ - "\50\3\4\0\136\3\21\0\30\3\70\0\20\3\u0200\0\u19b6\3\112\0"+ - "\u51a6\3\132\0\u048d\3\u0773\0\u2ba4\3\u215c\0\u012e\3\2\0\73\3\225\0"+ - "\7\3\14\0\5\3\5\0\1\3\1\0\12\3\1\0\15\3\1\0"+ - "\5\3\1\0\1\3\1\0\2\3\1\0\2\3\1\0\154\3\41\0"+ - "\u016b\3\22\0\100\3\2\0\66\3\50\0\15\3\66\0\2\3\30\0"+ - "\3\3\31\0\1\3\6\0\5\3\1\0\207\3\7\0\1\3\34\0"+ - "\32\3\4\0\1\3\1\0\32\3\12\0\132\3\3\0\6\3\2\0"+ - "\6\3\2\0\6\3\2\0\3\3\3\0\2\3\3\0\2\3\31\0"; + "\11\0\1\1\1\12\1\0\2\1\22\0\1\1\3\0\1\3\5\0"+ + "\1\10\3\0\1\4\1\7\12\2\6\0\1\11\32\3\1\5\1\13"+ + "\1\6\1\0\1\3\1\0\32\3\47\0\4\3\4\0\1\3\12\0"+ + "\1\3\4\0\1\3\5\0\27\3\1\0\37\3\1\0\u013f\3\31\0"+ + "\162\3\4\0\14\3\16\0\5\3\11\0\1\3\213\0\1\3\13\0"+ + "\1\3\1\0\3\3\1\0\1\3\1\0\24\3\1\0\54\3\1\0"+ + "\46\3\1\0\5\3\4\0\202\3\10\0\105\3\1\0\46\3\2\0"+ + "\2\3\6\0\20\3\41\0\46\3\2\0\1\3\7\0\47\3\110\0"+ + "\33\3\5\0\3\3\56\0\32\3\5\0\13\3\43\0\2\3\1\0"+ + "\143\3\1\0\1\3\17\0\2\3\7\0\2\3\12\0\3\3\2\0"+ + "\1\3\20\0\1\3\1\0\36\3\35\0\3\3\60\0\46\3\13\0"+ + "\1\3\u0152\0\66\3\3\0\1\3\22\0\1\3\7\0\12\3\43\0"+ + "\10\3\2\0\2\3\2\0\26\3\1\0\7\3\1\0\1\3\3\0"+ + "\4\3\3\0\1\3\36\0\2\3\1\0\3\3\16\0\4\3\21\0"+ + "\6\3\4\0\2\3\2\0\26\3\1\0\7\3\1\0\2\3\1\0"+ + "\2\3\1\0\2\3\37\0\4\3\1\0\1\3\23\0\3\3\20\0"+ + "\11\3\1\0\3\3\1\0\26\3\1\0\7\3\1\0\2\3\1\0"+ + "\5\3\3\0\1\3\22\0\1\3\17\0\2\3\17\0\1\3\23\0"+ + "\10\3\2\0\2\3\2\0\26\3\1\0\7\3\1\0\2\3\1\0"+ + "\5\3\3\0\1\3\36\0\2\3\1\0\3\3\17\0\1\3\21\0"+ + "\1\3\1\0\6\3\3\0\3\3\1\0\4\3\3\0\2\3\1\0"+ + "\1\3\1\0\2\3\3\0\2\3\3\0\3\3\3\0\10\3\1\0"+ + "\3\3\77\0\1\3\13\0\10\3\1\0\3\3\1\0\27\3\1\0"+ + "\12\3\1\0\5\3\46\0\2\3\43\0\10\3\1\0\3\3\1\0"+ + "\27\3\1\0\12\3\1\0\5\3\3\0\1\3\40\0\1\3\1\0"+ + "\2\3\43\0\10\3\1\0\3\3\1\0\27\3\1\0\20\3\46\0"+ + "\2\3\43\0\22\3\3\0\30\3\1\0\11\3\1\0\1\3\2\0"+ + "\7\3\72\0\60\3\1\0\2\3\13\0\10\3\72\0\2\3\1\0"+ + "\1\3\2\0\2\3\1\0\1\3\2\0\1\3\6\0\4\3\1\0"+ + "\7\3\1\0\3\3\1\0\1\3\1\0\1\3\2\0\2\3\1\0"+ + "\4\3\1\0\2\3\11\0\1\3\2\0\5\3\1\0\1\3\25\0"+ + "\2\3\42\0\1\3\77\0\10\3\1\0\42\3\35\0\4\3\164\0"+ + "\42\3\1\0\5\3\1\0\2\3\45\0\6\3\112\0\46\3\12\0"+ + "\51\3\7\0\132\3\5\0\104\3\5\0\122\3\6\0\7\3\1\0"+ + "\77\3\1\0\1\3\1\0\4\3\2\0\7\3\1\0\1\3\1\0"+ + "\4\3\2\0\47\3\1\0\1\3\1\0\4\3\2\0\37\3\1\0"+ + "\1\3\1\0\4\3\2\0\7\3\1\0\1\3\1\0\4\3\2\0"+ + "\7\3\1\0\7\3\1\0\27\3\1\0\37\3\1\0\1\3\1\0"+ + "\4\3\2\0\7\3\1\0\47\3\1\0\23\3\105\0\125\3\14\0"+ + "\u026c\3\2\0\10\3\12\0\32\3\5\0\113\3\3\0\3\3\17\0"+ + "\15\3\1\0\4\3\16\0\22\3\16\0\22\3\16\0\15\3\1\0"+ + "\3\3\17\0\64\3\43\0\1\3\3\0\2\3\103\0\130\3\10\0"+ + "\51\3\127\0\35\3\63\0\36\3\2\0\5\3\u038b\0\154\3\224\0"+ + "\234\3\4\0\132\3\6\0\26\3\2\0\6\3\2\0\46\3\2\0"+ + "\6\3\2\0\10\3\1\0\1\3\1\0\1\3\1\0\1\3\1\0"+ + "\37\3\2\0\65\3\1\0\7\3\1\0\1\3\3\0\3\3\1\0"+ + "\7\3\3\0\4\3\2\0\6\3\4\0\15\3\5\0\3\3\1\0"+ + "\7\3\102\0\2\3\23\0\1\3\34\0\1\3\15\0\1\3\40\0"+ + "\22\3\120\0\1\3\4\0\1\3\2\0\12\3\1\0\1\3\3\0"+ + "\5\3\6\0\1\3\1\0\1\3\1\0\1\3\1\0\4\3\1\0"+ + "\3\3\1\0\7\3\3\0\3\3\5\0\5\3\26\0\44\3\u0e81\0"+ + "\3\3\31\0\11\3\7\0\5\3\2\0\5\3\4\0\126\3\6\0"+ + "\3\3\1\0\137\3\5\0\50\3\4\0\136\3\21\0\30\3\70\0"+ + "\20\3\u0200\0\u19b6\3\112\0\u51a6\3\132\0\u048d\3\u0773\0\u2ba4\3\u215c\0"+ + "\u012e\3\2\0\73\3\225\0\7\3\14\0\5\3\5\0\1\3\1\0"+ + "\12\3\1\0\15\3\1\0\5\3\1\0\1\3\1\0\2\3\1\0"+ + "\2\3\1\0\154\3\41\0\u016b\3\22\0\100\3\2\0\66\3\50\0"+ + "\15\3\66\0\2\3\30\0\3\3\31\0\1\3\6\0\5\3\1\0"+ + "\207\3\7\0\1\3\34\0\32\3\4\0\1\3\1\0\32\3\12\0"+ + "\132\3\3\0\6\3\2\0\6\3\2\0\6\3\2\0\3\3\3\0"+ + "\2\3\3\0\2\3\31\0"; /** * Translates characters to character classes @@ -143,10 +159,10 @@ class _KDocLexer implements FlexLexer { private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); private static final String ZZ_ROWMAP_PACKED_0 = - "\0\0\0\15\0\32\0\47\0\64\0\101\0\116\0\133"+ - "\0\101\0\150\0\165\0\202\0\217\0\133\0\234\0\101"+ - "\0\251\0\266\0\165\0\133\0\303\0\101\0\133\0\320"+ - "\0\101\0\335\0\101\0\101"; + "\0\0\0\14\0\30\0\44\0\60\0\74\0\110\0\124"+ + "\0\74\0\140\0\154\0\170\0\204\0\124\0\220\0\74"+ + "\0\234\0\250\0\154\0\124\0\264\0\74\0\124\0\300"+ + "\0\74\0\314\0\74\0\74"; private static int [] zzUnpackRowMap() { int [] result = new int[28]; @@ -172,19 +188,19 @@ class _KDocLexer implements FlexLexer { private static final int [] ZZ_TRANS = zzUnpackTrans(); private static final String ZZ_TRANS_PACKED_0 = - "\10\6\1\7\1\10\1\6\1\0\1\6\1\11\1\12"+ - "\4\11\1\13\2\11\1\14\1\11\1\12\1\15\1\11"+ - "\1\12\4\11\1\13\2\11\1\16\1\17\1\12\1\15"+ - "\1\20\1\21\1\20\1\22\2\20\1\23\2\20\1\24"+ - "\1\20\1\21\1\20\1\11\1\12\4\11\1\13\2\11"+ - "\1\16\1\11\1\12\1\15\26\0\1\25\13\0\1\26"+ - "\1\27\4\0\1\12\11\0\1\12\4\0\1\30\21\0"+ - "\1\26\1\14\11\0\2\31\10\0\1\32\12\0\1\21"+ - "\11\0\1\21\3\0\3\22\21\0\1\33\5\0\4\30"+ - "\1\0\1\34\7\0\2\32\11\0"; + "\7\6\1\7\1\10\1\6\1\0\1\6\1\11\1\12"+ + "\3\11\1\13\2\11\1\14\1\11\1\12\1\15\1\11"+ + "\1\12\3\11\1\13\2\11\1\16\1\17\1\12\1\15"+ + "\1\20\1\21\1\20\1\22\1\20\1\23\2\20\1\24"+ + "\1\20\1\21\1\20\1\11\1\12\3\11\1\13\2\11"+ + "\1\16\1\11\1\12\1\15\24\0\1\25\12\0\1\26"+ + "\1\27\4\0\1\12\10\0\1\12\4\0\1\30\17\0"+ + "\1\26\1\14\10\0\2\31\10\0\1\32\11\0\1\21"+ + "\10\0\1\21\3\0\3\22\17\0\1\33\5\0\3\30"+ + "\1\0\1\34\7\0\2\32\10\0"; private static int [] zzUnpackTrans() { - int [] result = new int[234]; + int [] result = new int[216]; int offset = 0; offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); return result; @@ -333,7 +349,7 @@ class _KDocLexer implements FlexLexer { char [] map = new char[0x10000]; int i = 0; /* index in packed string */ int j = 0; /* index in unpacked array */ - while (i < 1220) { + while (i < 1208) { int count = packed.charAt(i++); char value = packed.charAt(i++); do map[j++] = value; while (--count > 0); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/parser/KDocElementType.java b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/parser/KDocElementType.java index 4993d8b2a08..86c2f06b4f9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/parser/KDocElementType.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/parser/KDocElementType.java @@ -17,26 +17,26 @@ package org.jetbrains.kotlin.kdoc.parser; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.idea.JetLanguage; -import org.jetbrains.kotlin.kdoc.psi.impl.KDocElementImpl; import java.lang.reflect.Constructor; public class KDocElementType extends IElementType { - private final Constructor psiFactory; + private final Constructor psiFactory; - public KDocElementType(String debugName, @NotNull Class psiClass) { + public KDocElementType(String debugName, @NotNull Class psiClass) { super(debugName, JetLanguage.INSTANCE); try { - psiFactory = psiClass != null ? psiClass.getConstructor(ASTNode.class) : null; + psiFactory = psiClass.getConstructor(ASTNode.class); } catch (NoSuchMethodException e) { throw new RuntimeException("Must have a constructor with ASTNode"); } } - public KDocElementImpl createPsi(ASTNode node) { + public PsiElement createPsi(ASTNode node) { assert node.getElementType() == this; try { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/parser/KDocElementTypes.java b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/parser/KDocElementTypes.java index 6ff530e4cf4..0faea9b570f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/parser/KDocElementTypes.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/parser/KDocElementTypes.java @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.kdoc.parser; import org.jetbrains.kotlin.kdoc.psi.impl.KDocLink; +import org.jetbrains.kotlin.kdoc.psi.impl.KDocName; import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection; import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag; @@ -24,4 +25,5 @@ public class KDocElementTypes { public static final KDocElementType KDOC_SECTION = new KDocElementType("KDOC_SECTION", KDocSection.class); public static final KDocElementType KDOC_TAG = new KDocElementType("KDOC_TAG", KDocTag.class); public static final KDocElementType KDOC_LINK = new KDocElementType("KDOC_LINK", KDocLink.class); + public static final KDocElementType KDOC_NAME = new KDocElementType("KDOC_NAME", KDocName.class); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/parser/KDocLinkParser.kt b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/parser/KDocLinkParser.kt new file mode 100644 index 00000000000..35c151b0aad --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/parser/KDocLinkParser.kt @@ -0,0 +1,69 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.kdoc.parser + +import com.intellij.lang.PsiParser +import com.intellij.psi.tree.IElementType +import com.intellij.lang.PsiBuilder +import com.intellij.lang.ASTNode +import org.jetbrains.kotlin.lexer.JetTokens + +/** + * Parses the contents of a Markdown link in KDoc. Uses the standard Kotlin lexer. + */ +class KDocLinkParser(): PsiParser { + override fun parse(root: IElementType, builder: PsiBuilder): ASTNode { + builder.setDebugMode(true) + val rootMarker = builder.mark() + if (builder.getTokenType() == JetTokens.LBRACKET) { + builder.advanceLexer() + } + parseQualifiedName(builder) + if (!builder.eof() && builder.getTokenType() != JetTokens.RBRACKET) { + builder.error("Closing bracket expected") + while (!builder.eof() && builder.getTokenType() != JetTokens.RBRACKET) { + builder.advanceLexer() + } + } + if (builder.getTokenType() == JetTokens.RBRACKET) { + builder.advanceLexer() + } + rootMarker.done(root) + return builder.getTreeBuilt() + } + + private fun parseQualifiedName(builder: PsiBuilder) { + var marker = builder.mark() + while (true) { + // don't highlight a word in a link as an error if it happens to be a Kotlin keyword + if (!isName(builder.getTokenType())) { + marker.drop() + builder.error("Identifier expected") + break + } + builder.advanceLexer() + marker.done(KDocElementTypes.KDOC_NAME) + if (builder.getTokenType() != JetTokens.DOT) { + break + } + marker = marker.precede() + builder.advanceLexer() + } + } + + private fun isName(tokenType: IElementType) = tokenType == JetTokens.IDENTIFIER || tokenType in JetTokens.KEYWORDS +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/parser/KDocParser.java b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/parser/KDocParser.java index 288346f243b..4a347858a4e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/parser/KDocParser.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/parser/KDocParser.java @@ -74,7 +74,9 @@ public class KDocParser implements PsiParser { if (knownTag != null && knownTag.isReferenceRequired() && builder.getTokenType() == KDocTokens.TEXT_OR_LINK) { PsiBuilder.Marker referenceMarker = builder.mark(); + PsiBuilder.Marker nameMarker = builder.mark(); builder.advanceLexer(); + nameMarker.done(KDocElementTypes.KDOC_NAME); referenceMarker.done(KDocElementTypes.KDOC_LINK); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocName.kt b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocName.kt new file mode 100644 index 00000000000..61391115ee0 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/kdoc/psi/impl/KDocName.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.kdoc.psi.impl + +import com.intellij.lang.ASTNode +import org.jetbrains.kotlin.psi.JetElementImpl + +/** + * A single part of a qualified name in the tag subject or link. + */ +public class KDocName(node: ASTNode): JetElementImpl(node) { + +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetParserDefinition.java b/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetParserDefinition.java index 66a812a949f..f03dbb9dd49 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetParserDefinition.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/parsing/JetParserDefinition.java @@ -33,7 +33,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.JetNodeType; import org.jetbrains.kotlin.JetNodeTypes; import org.jetbrains.kotlin.idea.JetLanguage; +import org.jetbrains.kotlin.kdoc.lexer.KDocTokens; import org.jetbrains.kotlin.kdoc.parser.KDocElementType; +import org.jetbrains.kotlin.kdoc.psi.impl.KDocLink; import org.jetbrains.kotlin.lexer.JetLexer; import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.psi.JetFile; @@ -106,6 +108,9 @@ public class JetParserDefinition implements ParserDefinition { else if (elementType instanceof KDocElementType) { return ((KDocElementType) elementType).createPsi(astNode); } + else if (elementType == KDocTokens.MARKDOWN_LINK) { + return new KDocLink(astNode); + } else { return ((JetNodeType) elementType).createPsi(astNode); } diff --git a/compiler/testData/psi/kdoc/Markdown.txt b/compiler/testData/psi/kdoc/Markdown.txt index 3dc99a1e0f3..19db5898e7a 100644 --- a/compiler/testData/psi/kdoc/Markdown.txt +++ b/compiler/testData/psi/kdoc/Markdown.txt @@ -8,7 +8,11 @@ JetFile: Markdown.kt PsiElement(KDOC_LEADING_ASTERISK)('*') PsiElement(KDOC_TEXT)(' ') KDOC_LINK - PsiElement(KDOC_MARKDOWN_LINK)('[WikiLink]') + KDOC_MARKDOWN_LINK + PsiElement(LBRACKET)('[') + KDOC_NAME + PsiElement(IDENTIFIER)('WikiLink') + PsiElement(RBRACKET)(']') PsiWhiteSpace('\n ') PsiElement(KDOC_LEADING_ASTERISK)('*') PsiElement(KDOC_TEXT)(' ') @@ -18,7 +22,11 @@ JetFile: Markdown.kt PsiElement(KDOC_LEADING_ASTERISK)('*') PsiElement(KDOC_TEXT)(' [') KDOC_LINK - PsiElement(KDOC_MARKDOWN_LINK)('[DoubleQuotedLink]') + KDOC_MARKDOWN_LINK + PsiElement(LBRACKET)('[') + KDOC_NAME + PsiElement(IDENTIFIER)('DoubleQuotedLink') + PsiElement(RBRACKET)(']') PsiElement(KDOC_TEXT)(']') PsiWhiteSpace('\n ') PsiElement(KDOC_LEADING_ASTERISK)('*') diff --git a/compiler/testData/psi/kdoc/MarkdownQualifiedName.kt b/compiler/testData/psi/kdoc/MarkdownQualifiedName.kt new file mode 100644 index 00000000000..27ead6e4e0e --- /dev/null +++ b/compiler/testData/psi/kdoc/MarkdownQualifiedName.kt @@ -0,0 +1,5 @@ +/** + * [A.B.C] + * [[System.out]] + * [System.in] + */ diff --git a/compiler/testData/psi/kdoc/MarkdownQualifiedName.txt b/compiler/testData/psi/kdoc/MarkdownQualifiedName.txt new file mode 100644 index 00000000000..058ba87e026 --- /dev/null +++ b/compiler/testData/psi/kdoc/MarkdownQualifiedName.txt @@ -0,0 +1,48 @@ +JetFile: MarkdownQualifiedName.kt + PACKAGE_DIRECTIVE + + KDoc + PsiElement(KDOC_START)('/**') + PsiWhiteSpace('\n ') + KDOC_SECTION + PsiElement(KDOC_LEADING_ASTERISK)('*') + PsiElement(KDOC_TEXT)(' ') + KDOC_LINK + KDOC_MARKDOWN_LINK + PsiElement(LBRACKET)('[') + KDOC_NAME + KDOC_NAME + KDOC_NAME + PsiElement(IDENTIFIER)('A') + PsiElement(DOT)('.') + PsiElement(IDENTIFIER)('B') + PsiElement(DOT)('.') + PsiElement(IDENTIFIER)('C') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n ') + PsiElement(KDOC_LEADING_ASTERISK)('*') + PsiElement(KDOC_TEXT)(' [') + KDOC_LINK + KDOC_MARKDOWN_LINK + PsiElement(LBRACKET)('[') + KDOC_NAME + KDOC_NAME + PsiElement(IDENTIFIER)('System') + PsiElement(DOT)('.') + PsiElement(IDENTIFIER)('out') + PsiElement(RBRACKET)(']') + PsiElement(KDOC_TEXT)(']') + PsiWhiteSpace('\n ') + PsiElement(KDOC_LEADING_ASTERISK)('*') + PsiElement(KDOC_TEXT)(' ') + KDOC_LINK + KDOC_MARKDOWN_LINK + PsiElement(LBRACKET)('[') + KDOC_NAME + KDOC_NAME + PsiElement(IDENTIFIER)('System') + PsiElement(DOT)('.') + PsiElement(in)('in') + PsiElement(RBRACKET)(']') + PsiWhiteSpace('\n ') + PsiElement(KDOC_END)('*/') \ No newline at end of file diff --git a/compiler/testData/psi/kdoc/ParamTag.txt b/compiler/testData/psi/kdoc/ParamTag.txt index 9c59b997775..ba38939f4a3 100644 --- a/compiler/testData/psi/kdoc/ParamTag.txt +++ b/compiler/testData/psi/kdoc/ParamTag.txt @@ -11,7 +11,8 @@ JetFile: ParamTag.kt PsiElement(KDOC_TAG_NAME)('@param') PsiWhiteSpace(' ') KDOC_LINK - PsiElement(KDOC_TEXT_OR_LINK)('a') + KDOC_NAME + PsiElement(KDOC_TEXT_OR_LINK)('a') PsiElement(KDOC_TEXT)(' The description of a.') PsiWhiteSpace('\n ') PsiElement(KDOC_END)('*/') \ No newline at end of file diff --git a/compiler/testData/psi/kdoc/ParamTagAtStart.txt b/compiler/testData/psi/kdoc/ParamTagAtStart.txt index 54d53bf16a7..7ef28c97ccb 100644 --- a/compiler/testData/psi/kdoc/ParamTagAtStart.txt +++ b/compiler/testData/psi/kdoc/ParamTagAtStart.txt @@ -9,6 +9,7 @@ JetFile: ParamTagAtStart.kt PsiElement(KDOC_TAG_NAME)('@param') PsiWhiteSpace(' ') KDOC_LINK - PsiElement(KDOC_TEXT_OR_LINK)('a') + KDOC_NAME + PsiElement(KDOC_TEXT_OR_LINK)('a') PsiElement(KDOC_TEXT)(' this is a ') PsiElement(KDOC_END)('*/') \ No newline at end of file diff --git a/compiler/testData/psi/kdoc/ReturnWithBrackets.txt b/compiler/testData/psi/kdoc/ReturnWithBrackets.txt index 554d1a069e9..88a29c7d6d6 100644 --- a/compiler/testData/psi/kdoc/ReturnWithBrackets.txt +++ b/compiler/testData/psi/kdoc/ReturnWithBrackets.txt @@ -18,7 +18,11 @@ JetFile: ReturnWithBrackets.kt KDOC_TAG PsiElement(KDOC_TAG_NAME)('@return') KDOC_LINK - PsiElement(KDOC_MARKDOWN_LINK)('[x]') + KDOC_MARKDOWN_LINK + PsiElement(LBRACKET)('[') + KDOC_NAME + PsiElement(IDENTIFIER)('x') + PsiElement(RBRACKET)(']') PsiElement(KDOC_TEXT)(' This is a reference') PsiWhiteSpace('\n ') PsiElement(KDOC_END)('*/') \ No newline at end of file diff --git a/compiler/testData/psi/kdoc/Sections.txt b/compiler/testData/psi/kdoc/Sections.txt index 30080e32e6c..fea98521a10 100644 --- a/compiler/testData/psi/kdoc/Sections.txt +++ b/compiler/testData/psi/kdoc/Sections.txt @@ -14,7 +14,8 @@ JetFile: Sections.kt PsiElement(KDOC_TAG_NAME)('@param') PsiWhiteSpace(' ') KDOC_LINK - PsiElement(KDOC_TEXT_OR_LINK)('T') + KDOC_NAME + PsiElement(KDOC_TEXT_OR_LINK)('T') PsiElement(KDOC_TEXT)(' a type parameter.') PsiWhiteSpace('\n ') PsiElement(KDOC_LEADING_ASTERISK)('*') @@ -32,7 +33,8 @@ JetFile: Sections.kt PsiElement(KDOC_TAG_NAME)('@param') PsiWhiteSpace(' ') KDOC_LINK - PsiElement(KDOC_TEXT_OR_LINK)('a') + KDOC_NAME + PsiElement(KDOC_TEXT_OR_LINK)('a') PsiElement(KDOC_TEXT)(' a constructor parameter.') PsiWhiteSpace('\n ') PsiElement(KDOC_END)('*/') \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java index 81223dfb149..7f458996a41 100644 --- a/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/parsing/JetParsingTestGenerated.java @@ -1085,6 +1085,12 @@ public class JetParsingTestGenerated extends AbstractJetParsingTest { doParsingTest(fileName); } + @TestMetadata("MarkdownQualifiedName.kt") + public void testMarkdownQualifiedName() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/kdoc/MarkdownQualifiedName.kt"); + doParsingTest(fileName); + } + @TestMetadata("ParamTag.kt") public void testParamTag() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/psi/kdoc/ParamTag.kt");