From 92e5551f743c3efa5123459cc2d34c7b7e76241e Mon Sep 17 00:00:00 2001 From: Andrey Kuleshov Date: Sat, 12 Feb 2022 02:23:38 +0300 Subject: [PATCH] Initial implementation of ArrayOfTables ### What's done: - Small refactoring related to sealed classes limitations - Initial test impplemetation of array of tables - Kotlin update to 1.6.10 --- build.gradle.kts | 4 ++ diktat-analysis.yml | 2 +- ktoml-core/build.gradle.kts | 2 - .../akuleshov7/ktoml/parsers/TomlParser.kt | 3 +- .../ktoml/tree/TomlArrayOfTables.kt | 40 +++++++++---------- .../com/akuleshov7/ktoml/tree/TomlFile.kt | 5 ++- .../ktoml/tree/TomlKeyValueArray.kt | 7 +++- .../ktoml/tree/TomlKeyValuePrimitive.kt | 8 +++- .../com/akuleshov7/ktoml/tree/TomlNode.kt | 20 ++++++---- .../ktoml/tree/TomlStubEmptyNode.kt | 3 +- .../com/akuleshov7/ktoml/tree/TomlTable.kt | 30 ++++++++++---- .../ktoml/tree/TomlTablePrimitive.kt | 12 +++--- .../com/akuleshov7/ktoml/tree/TomlValue.kt | 3 +- .../akuleshov7/ktoml/writers/TomlEmitter.kt | 3 +- ktoml-file/build.gradle.kts | 1 - 15 files changed, 87 insertions(+), 56 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 88391e22..c997f44d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,6 +13,10 @@ allprojects { } configureDiktat() configureDetekt() + + tasks.withType { + jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED") + } } createDiktatTask() createDetektTask() diff --git a/diktat-analysis.yml b/diktat-analysis.yml index db1b6914..90412414 100644 --- a/diktat-analysis.yml +++ b/diktat-analysis.yml @@ -32,7 +32,7 @@ configuration: useRecommendedImportsOrder: true - name: FILE_WILDCARD_IMPORTS - enabled: true + enabled: false configuration: allowedWildcards: "kotlinx.serialization.*" - name: BRACES_BLOCK_STRUCTURE_ERROR diff --git a/ktoml-core/build.gradle.kts b/ktoml-core/build.gradle.kts index 59d344e7..38c005f2 100644 --- a/ktoml-core/build.gradle.kts +++ b/ktoml-core/build.gradle.kts @@ -1,6 +1,4 @@ import com.akuleshov7.buildutils.configurePublishing -import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.getCurrentOperatingSystem -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest plugins { diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/parsers/TomlParser.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/parsers/TomlParser.kt index dbfbf068..81c81a8c 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/parsers/TomlParser.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/parsers/TomlParser.kt @@ -32,6 +32,7 @@ public value class TomlParser(private val config: TomlConfig) { * @return the root node of the resulted toml tree * @throws InternalAstException - if toml node does not inherit TomlNode class */ + @Suppress("TOO_LONG_FUNCTION") public fun parseStringsToTomlTree(tomlLines: List, config: TomlConfig): TomlFile { var currentParentalNode: TomlNode = TomlFile(config) val tomlFileHead = currentParentalNode as TomlFile @@ -74,7 +75,7 @@ public value class TomlParser(private val config: TomlConfig) { throw InternalAstException("All Toml nodes should always inherit TomlNode class." + " Check [${keyValue.key}] with $keyValue type") } - + // inserting the key-value record to the tree if (keyValue.key.isDotted) { // in case parser has faced dot-separated complex key (a.b.c) it should create proper table [a.b], // because table is the same as dotted key diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlArrayOfTables.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlArrayOfTables.kt index 57ddb9f5..16dbfa0a 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlArrayOfTables.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlArrayOfTables.kt @@ -1,3 +1,7 @@ +/** + * Array of tables https://toml.io/en/v1.0.0#array-of-tables + */ + package com.akuleshov7.ktoml.tree import com.akuleshov7.ktoml.TomlConfig @@ -6,36 +10,31 @@ import com.akuleshov7.ktoml.parsers.splitKeyToTokens import com.akuleshov7.ktoml.parsers.trimDoubleBrackets import com.akuleshov7.ktoml.parsers.trimQuotes +/** + * @property isSynthetic + */ // FixMe: this class is mostly identical to the TomlTable - we should unify them together public class TomlArrayOfTables( content: String, lineNo: Int, config: TomlConfig = TomlConfig(), public val isSynthetic: Boolean = false -) : TomlTable(content, lineNo, config) { +) : TomlTable( + content, + lineNo, + config +) { public override val type: TableType = TableType.ARRAY + // short table name (only the name without parental prefix, like a - it is used in decoder and encoder) + override val name: String + // list of tables (including sub-tables) that are included in this table (e.g.: {a, a.b, a.b.c} in a.b.c) public override lateinit var tablesList: List // full name of the table (like a.b.c.d) public override lateinit var fullTableName: String - // short table name (only the name without parental prefix, like a - it is used in decoder and encoder) - override val name: String - - internal val keyValues: MutableList> = mutableListOf() - - internal fun insertKeyValue(keyValue: TomlKeyValue, isNewElementInArray: Boolean) { - if (isNewElementInArray) { - // creating a new bucket for the array - keyValues.add(mutableListOf(keyValue)) - } else { - // adding new keyValue to the last bucket (it should have been created on the previous step) - keyValues[keyValues.lastIndex].add(keyValue) - } - } - init { // getting the content inside brackets ([a.b] -> a.b) val sectionFromContent = content.trim().trimDoubleBrackets().trim() @@ -55,15 +54,12 @@ public class TomlArrayOfTables( } /** - * this is a hack to cover empty TOML tables that have missing key-values - * According the spec: "Empty tables are allowed and simply have no key/value pairs within them." - * - * Instances of this stub will be added as children to such parsed tables + * This class is used to store elements of array of tables (bucket for key-value records) */ public class TomlArrayOfTablesElement(lineNo: Int, config: TomlConfig = TomlConfig()) : TomlNode( EMPTY_TECHNICAL_NODE, lineNo, - config) { + config +) { override val name: String = EMPTY_TECHNICAL_NODE } - diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlFile.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlFile.kt index af8bf387..ae29d750 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlFile.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlFile.kt @@ -9,9 +9,10 @@ import com.akuleshov7.ktoml.exceptions.InternalAstException public class TomlFile(config: TomlConfig = TomlConfig()) : TomlNode( "rootNode", 0, - config) { + config +) { override val name: String = "rootNode" override fun getNeighbourNodes(): MutableSet = - throw InternalAstException("Invalid call to getNeighbourNodes() for TomlFile node") + throw InternalAstException("Invalid call to getNeighbourNodes() for TomlFile node") } diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValueArray.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValueArray.kt index 882c7fde..1ae208a1 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValueArray.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValueArray.kt @@ -16,7 +16,12 @@ public class TomlKeyValueArray( override val lineNo: Int, override val name: String, config: TomlConfig = TomlConfig() -) : TomlNode(key, value, lineNo, config), TomlKeyValue { +) : TomlNode( + key, + value, + lineNo, + config +), TomlKeyValue { // adaptor for a string pair of key-value public constructor( keyValuePair: Pair, diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValuePrimitive.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValuePrimitive.kt index 5eb6acef..ea7022d6 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValuePrimitive.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlKeyValuePrimitive.kt @@ -15,7 +15,12 @@ public class TomlKeyValuePrimitive( override val lineNo: Int, override val name: String, config: TomlConfig = TomlConfig() -) : TomlNode(key, value, lineNo, config), TomlKeyValue { +) : TomlNode( + key, + value, + lineNo, + config +), TomlKeyValue { // adaptor for a string pair of key-value public constructor( keyValuePair: Pair, @@ -28,4 +33,3 @@ public class TomlKeyValuePrimitive( TomlKey(keyValuePair.first, lineNo).content ) } - diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlNode.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlNode.kt index 76c6bf8f..df390980 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlNode.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlNode.kt @@ -4,7 +4,6 @@ package com.akuleshov7.ktoml.tree -import com.akuleshov7.ktoml.Toml import com.akuleshov7.ktoml.TomlConfig import com.akuleshov7.ktoml.exceptions.ParseException @@ -38,7 +37,8 @@ public sealed class TomlNode( key: TomlKey, value: TomlValue, lineNo: Int, - config: TomlConfig = TomlConfig()) : this( + config: TomlConfig = TomlConfig() + ) : this( "${key.content}=${value.content}", lineNo, config @@ -75,9 +75,9 @@ public sealed class TomlNode( type: TableType ): List { val result = - // we need to filter nodes by the type of table that we are inserting to the tree (array/primitive) + // we need to filter nodes by the type of table that we are inserting to the tree (array/primitive) if (this is TomlTable && this.type == type && - this.fullTableName == searchedTableName && currentLevel == searchedLevel) { + this.fullTableName == searchedTableName && currentLevel == searchedLevel) { mutableListOf(this) } else { mutableListOf() @@ -104,10 +104,15 @@ public sealed class TomlNode( * a.c a.d * \ * a.d.e + * @param type * @return table that was found or null in case of not found * @throws ParseException if found several tables with the same name */ - public fun findTableInAstByName(searchedTableName: String, searchedLevel: Int, type: TableType): TomlTable? { + public fun findTableInAstByName( + searchedTableName: String, + searchedLevel: Int, + type: TableType + ): TomlTable? { val searchedTable = findTableInAstByName(searchedTableName, searchedLevel, 0, type) if (searchedTable.size > 1) { @@ -119,15 +124,15 @@ public sealed class TomlNode( return if (searchedTable.isEmpty()) null else searchedTable[0] } - /** * Method inserts a table (section) to tree. It parses the section name and creates all missing nodes in the tree * (even parental). For [a.b.c] it will create 3 nodes: a, b, and c * * @param tomlTable - a table (section) that should be inserted into the tree + * @param type * @return inserted table */ - public fun insertTableToTree(tomlTable: T, type: TableType): TomlNode { + public fun insertTableToTree(tomlTable: T, type: TableType): TomlNode { // prevParentNode - saved node that is used in a chain var prevParentNode: TomlNode = this // [a.b.c.d] -> for each section node checking existing node in a tree @@ -209,4 +214,3 @@ public sealed class TomlNode( } } } - diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlStubEmptyNode.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlStubEmptyNode.kt index 78be0c4e..9bee8f66 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlStubEmptyNode.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlStubEmptyNode.kt @@ -11,6 +11,7 @@ import com.akuleshov7.ktoml.TomlConfig public class TomlStubEmptyNode(lineNo: Int, config: TomlConfig = TomlConfig()) : TomlNode( EMPTY_TECHNICAL_NODE, lineNo, - config) { + config +) { override val name: String = EMPTY_TECHNICAL_NODE } diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlTable.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlTable.kt index f9f4cff2..6095fe47 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlTable.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlTable.kt @@ -1,22 +1,36 @@ +/** + * Common class for tables + */ + package com.akuleshov7.ktoml.tree import com.akuleshov7.ktoml.TomlConfig -import com.akuleshov7.ktoml.exceptions.ParseException /** - * Interface that contains all common methods that are used in KeyValue nodes + * Abstract class to represent all types of tables: primitive/arrays/etc. + * @property content - raw string name of the table + * @property lineNo - line number + * @property config - toml configuration */ -public abstract class TomlTable ( +public abstract class TomlTable( override val content: String, override val lineNo: Int, override val config: TomlConfig = TomlConfig() -): TomlNode(content, lineNo, config) { - abstract public var fullTableName: String - abstract public var tablesList: List - abstract public val type: TableType +) : TomlNode( + content, + lineNo, + config +) { + public abstract var fullTableName: String + public abstract var tablesList: List + public abstract val type: TableType } +/** + * Special Enum that is used in a logic related to insertion of tables to AST + */ public enum class TableType { ARRAY, - PRIMITIVE + PRIMITIVE, + ; } diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlTablePrimitive.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlTablePrimitive.kt index 0bc545ba..d5bc8fee 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlTablePrimitive.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlTablePrimitive.kt @@ -20,18 +20,20 @@ public class TomlTablePrimitive( content: String, lineNo: Int, config: TomlConfig = TomlConfig(), - public val isSynthetic: Boolean = false) : TomlTable( + public val isSynthetic: Boolean = false +) : TomlTable( content, lineNo, - config) { + config +) { public override val type: TableType = TableType.PRIMITIVE - // list of tables (including sub-tables) that are included in this table (e.g.: {a, a.b, a.b.c} in a.b.c) - public override lateinit var tablesList: List - // short table name (only the name without parental prefix, like a - it is used in decoder and encoder) override val name: String + // list of tables (including sub-tables) that are included in this table (e.g.: {a, a.b, a.b.c} in a.b.c) + public override lateinit var tablesList: List + // full name of the table (like a.b.c.d) public override lateinit var fullTableName: String diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlValue.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlValue.kt index 0af5521c..ecfcbd36 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlValue.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/TomlValue.kt @@ -204,7 +204,8 @@ internal constructor( ) : this( rawContent.parse(lineNo, config), rawContent, - lineNo) { + lineNo + ) { validateBrackets() } diff --git a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/writers/TomlEmitter.kt b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/writers/TomlEmitter.kt index 066f006c..d0beff21 100644 --- a/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/writers/TomlEmitter.kt +++ b/ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/writers/TomlEmitter.kt @@ -146,7 +146,8 @@ public abstract class TomlEmitter(config: TomlConfig) { public fun emitValue( string: String, isLiteral: Boolean = false, - isMultiline: Boolean = false): Unit = + isMultiline: Boolean = false + ): Unit = if (isMultiline) { val quotes = if (isLiteral) "'''" else "\"\"\"" diff --git a/ktoml-file/build.gradle.kts b/ktoml-file/build.gradle.kts index 587c61b5..2a93d6e3 100644 --- a/ktoml-file/build.gradle.kts +++ b/ktoml-file/build.gradle.kts @@ -1,5 +1,4 @@ import com.akuleshov7.buildutils.configurePublishing -import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.getCurrentOperatingSystem import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest plugins {