• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package parser.elements
18 
19 import lexer.ILexer
20 import lexer.Token
21 import lexer.TokenCategory
22 import lexer.TokenGrammar
23 import parser.peekPreviousToken
24 import parser.peekToken
25 import java.text.ParseException
26 
27 
28 class DocAnnotationParser(iter: ListIterator<Token>, var shouldResetIterator: Boolean = false) : AbstractParser(iter) {
29 
30     lateinit var tag: TokenGrammar
31     var arg: String? = null //some tags have arguments (eg. @param arg desc)
32     lateinit var description: String
33 
34     init {
35         parseTokens(scanTokens(iter))
36         if (shouldResetIterator) resetIterator(iter)
37     }
38 
formatValuenull39     private fun formatValue(tokens: List<Token>): String {
40         return if (tokens.isEmpty()) {
41             ""
42         } else {
43             tokens.map {
44                 when (it.identifier) {
45                     TokenGrammar.EMPTY_LINE -> "\n\n"
46                     else -> it.value
47                 }
48             }
49                     .joinToString(" ")
50                     .let { ILexer.unpadDelimiters(it) }
51         }
52     }
53 
54     /**
55      * Scan until: doc end token, empty line, another @param
56      */
scanTokensnull57     override fun scanTokens(iter: ListIterator<Token>): List<Token> {
58         val tokens = mutableListOf<Token>()
59         var token: Token
60 
61         //depending how invoked, queue up doc annotation token
62         if (peekToken(iter)?.identifier == TokenGrammar.AT) iter.next()
63         if (peekPreviousToken(iter)?.category == TokenCategory.DocAnnotation) iter.previous()
64 
65         if (peekToken(iter)!!.category != TokenCategory.DocAnnotation)
66             throw ParseException("Token sequence must begin with a DocAnnotation", this.indexStart)
67 
68         loop@ while (iter.hasNext()) {
69             token = iter.next()
70 
71             when {
72                 //descriptions don't span blank lines
73                 token.identifier == TokenGrammar.EMPTY_LINE -> break@loop
74 
75                 //if doc block ends or found next annotation tag, back up and bail
76                 token.identifier == TokenGrammar.DOC_END ||
77                 token.identifier == TokenGrammar.AT && peekToken(iter)?.category == TokenCategory.DocAnnotation -> {
78                     iter.previous()
79                     break@loop
80                 }
81 
82                 else -> tokens.add(token)
83             }
84         }
85         return tokens
86     }
87 
parseTokensnull88     override fun parseTokens(tokens: List<Token>) {
89         val iter = tokens.listIterator()
90         assert(iter.hasNext())
91         val token = iter.next()
92 
93         if (token.category != TokenCategory.DocAnnotation)
94             throw ParseException("Invalid doc anootation tag: ${token.value}", this.indexStart)
95 
96         //annotation tag name (must be in TokenGrammar)
97         this.tag = token.identifier
98 
99         //annotation tag can take an optional argument
100         //so can return (preferred). TODO: check HALs if mandatory
101         if (token.identifier == TokenGrammar.PARAM || token.identifier == TokenGrammar.RETURN) {
102             if (iter.hasNext()) this.arg = iter.next().value
103         }
104 
105         //the rest is annotation description
106         val descTokens = mutableListOf<Token>()
107         while (iter.hasNext()) {
108             descTokens.add(iter.next())
109         }
110 
111         this.description = if (descTokens.isEmpty()) {
112             ""
113         } else {
114             descTokens.map { if (it.identifier == TokenGrammar.EMPTY_LINE) "\n\n" else it.value }
115                     .joinToString(" ")
116                     .let { ILexer.unpadDelimiters(it) }
117         }
118     }
119 }