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.declarations 18 19 import lexer.Token 20 import lexer.TokenCategory 21 import lexer.TokenGrammar 22 import parser.elements.DocParser 23 import parser.peekToken 24 import writer.tokenValues 25 import java.text.ParseException 26 27 class EnumDeclarationParser(iter: ListIterator<Token>, var shouldResetIterator: Boolean = false) : AbstractDeclarationParser(iter) { 28 29 lateinit override var name: String 30 lateinit var type: String 31 var members = mutableListOf<EnumMember>() 32 33 init { 34 parseTokens(scanTokens(iter)) 35 if (shouldResetIterator) resetIterator(iter) 36 } 37 38 override fun parseTokens(tokens: List<Token>) { 39 val iter = tokens.listIterator() 40 var token = iter.next() 41 assert(token.identifier == TokenGrammar.ENUM) 42 assert(tokens.last().identifier == TokenGrammar.SEMICOLON) 43 44 //name 45 token = iter.next() 46 if (token.category != TokenCategory.Word) 47 throw ParseException("Invalid enum name: ${tokenValues(tokens)}", this.indexStart) 48 this.name = token.value 49 50 token = iter.next() //':' 51 if (token.identifier != TokenGrammar.COLON) 52 throw ParseException("Invalid enum type syntax: ${tokenValues(tokens)}", this.indexStart) 53 54 //type: can be type name or package 55 assert(iter.hasNext()) 56 val sb = StringBuilder() 57 while (iter.hasNext() && peekToken(iter)!!.identifier != TokenGrammar.BRACE_OPEN) { 58 sb.append(iter.next().value) 59 } 60 this.type = sb.toString() 61 62 //members 63 //convert iterator sequence of comma separated tokens to list of lists 64 scanDelimitedList(iter, openDelimiter = TokenGrammar.BRACE_OPEN, closeDelimiter = TokenGrammar.BRACE_CLOSE) 65 .forEach { 66 var statementTokens = it.toMutableList() 67 var docParser: DocParser? = null 68 assert(statementTokens.isNotEmpty()) 69 70 //If doc, extract doc tokens and parse, and remove from statement tokens 71 if (statementTokens.first().identifier == TokenGrammar.DOC_START) { 72 val idx = statementTokens.indexOfFirst { it.identifier == TokenGrammar.DOC_END } 73 if (idx == -1) throw ParseException("Unable to find doc_end", this.indexStart) 74 75 val docTokens = statementTokens.subList(0, idx+1) 76 docParser = DocParser(docTokens.listIterator()) 77 statementTokens = statementTokens.subList(idx+1, statementTokens.size) 78 } 79 if (statementTokens.isEmpty()) 80 throw ParseException("Invalid member in enum: ${tokenValues(tokens)}", this.indexStart) 81 val member = EnumMember(statementTokens) 82 member.docParser = docParser 83 this.members.add(member) 84 } 85 } 86 } 87 88 //split member: name [= value] 89 class EnumMember(tokens: List<Token>) { 90 val name: String 91 var value: String? = null 92 var docParser: DocParser? = null 93 94 init { 95 assert(tokens.isNotEmpty()) 96 this.name = tokens.first().value 97 98 //check for assignment, take right side 99 if (tokens.any { it.identifier == TokenGrammar.EQUAL }) { 100 this.value = tokens.takeLastWhile { it.identifier != TokenGrammar.EQUAL } 101 .map { it.value } 102 .joinToString(" ") 103 } 104 } 105 }