import TokenType.* import exceptions.* class Syntax { /** * Checks and validates whether the code complies with the syntax/grammar rules */ fun check(statements: MutableList>>): Boolean { statements.forEach { statement -> removePadding(statement) mergeStrings(statement) mergeTokens(statement) print(statement) statement.forEachIndexed { j, token -> when (token.second) { Keyword -> allowNext(statement, j, listOf(Assignment, Constant)) Constant -> allowNext(statement, j, listOf(Comparison, Arithmetic, Logical, Bracket)) Assignment -> allowNext(statement, j, listOf(Constant)) Arithmetic -> allowNext(statement, j, listOf(Constant)) Comparison -> allowNext(statement, j, listOf(Constant)) Logical -> allowNext(statement, j, listOf(Constant)) Identifier -> allowNext(statement, j, listOf(Keyword, Assignment)) Punctuation -> allowNext(statement, j, listOf(Constant)) Bracket -> allowNext(statement, j, listOf(Constant, Keyword, Logical, Assignment)) Classifier -> Unit Empty -> Unit Skip -> throw UnknownType(token.first) } } } return true } /** * Removes empty characters from the start and end of statements */ private fun removePadding(statement: MutableList>) { while (statement[0].second == Empty) statement.removeAt(0) while (statement[statement.size - 1].second == Empty) statement.removeAt(statement.size - 1) } /** * Merges classified strings to constants */ private fun mergeStrings(statement: MutableList>) { var stringing = false statement.forEachIndexed { i, token -> if (token.second == Classifier) stringing = !stringing if (stringing || token.second == Classifier) statement[i] = token.first to Constant } } /** * Merges tokens by same type */ private fun mergeTokens(statement: MutableList>) { var i = 0 while (statement.size > i + 1) { if (statement[i].second == statement[i + 1].second) { // TODO: Differentiate int and string statement[i] = statement[i].first + statement[i + 1].first to statement[i].second statement.removeAt(i + 1) i-- } i++ } } /** * Throws [SyntaxError] if the next token is not in [allowed] */ private fun allowNext(statement: MutableList>, index: kotlin.Int, allowed: List) { if (statement.size > index + 1 && nextNonEmpty(statement, index).second !in allowed) { throw SyntaxError(nextNonEmpty(statement, index)) } } /** * Finds the next non empty token by [index] */ private fun nextNonEmpty(statement: MutableList>, index: kotlin.Int): Pair { var i = index + 1 while (statement[i].second == Empty) i++ return statement[i] } }