blob: fb0fe641ac2668598e0ff90c2788e47af08a2c86 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* 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 parser.elements.declarations
import lexer.Token
import lexer.TokenCategory
import lexer.TokenGrammar
import parser.elements.DocParser
import parser.peekToken
import writer.tokenValues
import java.text.ParseException
class EnumDeclarationParser(iter: ListIterator<Token>, var shouldResetIterator: Boolean = false) : AbstractDeclarationParser(iter) {
lateinit override var name: String
lateinit var type: String
var members = mutableListOf<EnumMember>()
init {
parseTokens(scanTokens(iter))
if (shouldResetIterator) resetIterator(iter)
}
override fun parseTokens(tokens: List<Token>) {
val iter = tokens.listIterator()
var token = iter.next()
assert(token.identifier == TokenGrammar.ENUM)
assert(tokens.last().identifier == TokenGrammar.SEMICOLON)
//name
token = iter.next()
if (token.category != TokenCategory.Word)
throw ParseException("Invalid enum name: ${tokenValues(tokens)}", this.indexStart)
this.name = token.value
token = iter.next() //':'
if (token.identifier != TokenGrammar.COLON)
throw ParseException("Invalid enum type syntax: ${tokenValues(tokens)}", this.indexStart)
//type: can be type name or package
assert(iter.hasNext())
val sb = StringBuilder()
while (iter.hasNext() && peekToken(iter)!!.identifier != TokenGrammar.BRACE_OPEN) {
sb.append(iter.next().value)
}
this.type = sb.toString()
//members
//convert iterator sequence of comma separated tokens to list of lists
scanDelimitedList(iter, openDelimiter = TokenGrammar.BRACE_OPEN, closeDelimiter = TokenGrammar.BRACE_CLOSE)
.forEach {
var statementTokens = it.toMutableList()
var docParser: DocParser? = null
assert(statementTokens.isNotEmpty())
//If doc, extract doc tokens and parse, and remove from statement tokens
if (statementTokens.first().identifier == TokenGrammar.DOC_START) {
val idx = statementTokens.indexOfFirst { it.identifier == TokenGrammar.DOC_END }
if (idx == -1) throw ParseException("Unable to find doc_end", this.indexStart)
val docTokens = statementTokens.subList(0, idx+1)
docParser = DocParser(docTokens.listIterator())
statementTokens = statementTokens.subList(idx+1, statementTokens.size)
}
if (statementTokens.isEmpty())
throw ParseException("Invalid member in enum: ${tokenValues(tokens)}", this.indexStart)
val member = EnumMember(statementTokens)
member.docParser = docParser
this.members.add(member)
}
}
}
//split member: name [= value]
class EnumMember(tokens: List<Token>) {
val name: String
var value: String? = null
var docParser: DocParser? = null
init {
assert(tokens.isNotEmpty())
this.name = tokens.first().value
//check for assignment, take right side
if (tokens.any { it.identifier == TokenGrammar.EQUAL }) {
this.value = tokens.takeLastWhile { it.identifier != TokenGrammar.EQUAL }
.map { it.value }
.joinToString(" ")
}
}
}