001 /* 002 * Copyright 2010-2015 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.kotlin.kdoc.parser; 018 019 import com.intellij.lang.ASTNode; 020 import com.intellij.lang.PsiBuilder; 021 import com.intellij.lang.PsiParser; 022 import com.intellij.psi.tree.IElementType; 023 import org.jetbrains.annotations.NotNull; 024 import org.jetbrains.kotlin.kdoc.lexer.KDocTokens; 025 026 public class KDocParser implements PsiParser { 027 @Override 028 @NotNull 029 public ASTNode parse(IElementType root, PsiBuilder builder) { 030 PsiBuilder.Marker rootMarker = builder.mark(); 031 if (builder.getTokenType() == KDocTokens.START) { 032 builder.advanceLexer(); 033 } 034 PsiBuilder.Marker currentSectionMarker = builder.mark(); 035 036 // todo: parse KDoc tags, markdown, etc... 037 while (!builder.eof()) { 038 if (builder.getTokenType() == KDocTokens.TAG_NAME) { 039 currentSectionMarker = parseTag(builder, currentSectionMarker); 040 } 041 else if (builder.getTokenType() == KDocTokens.END) { 042 if (currentSectionMarker != null) { 043 currentSectionMarker.done(KDocElementTypes.KDOC_SECTION); 044 currentSectionMarker = null; 045 } 046 builder.advanceLexer(); 047 } 048 else { 049 builder.advanceLexer(); 050 } 051 } 052 053 if (currentSectionMarker != null) { 054 currentSectionMarker.done(KDocElementTypes.KDOC_SECTION); 055 } 056 rootMarker.done(root); 057 return builder.getTreeBuilt(); 058 } 059 060 private static PsiBuilder.Marker parseTag(PsiBuilder builder, PsiBuilder.Marker currentSectionMarker) { 061 String tagName = builder.getTokenText(); 062 KDocKnownTag knownTag = KDocKnownTag.findByTagName(tagName); 063 if (knownTag != null && knownTag.isSectionStart()) { 064 currentSectionMarker.done(KDocElementTypes.KDOC_SECTION); 065 currentSectionMarker = builder.mark(); 066 } 067 PsiBuilder.Marker tagStart = builder.mark(); 068 builder.advanceLexer(); 069 070 while (!builder.eof() && !isAtEndOfTag(builder)) { 071 builder.advanceLexer(); 072 } 073 tagStart.done(KDocElementTypes.KDOC_TAG); 074 return currentSectionMarker; 075 } 076 077 private static boolean isAtEndOfTag(PsiBuilder builder) { 078 if (builder.getTokenType() == KDocTokens.END) { 079 return true; 080 } 081 if (builder.getTokenType() == KDocTokens.LEADING_ASTERISK) { 082 int lookAheadCount = 1; 083 if (builder.lookAhead(1) == KDocTokens.TEXT) { 084 lookAheadCount++; 085 } 086 if (builder.lookAhead(lookAheadCount) == KDocTokens.TAG_NAME) { 087 return true; 088 } 089 } 090 return false; 091 } 092 }