diff --git a/build.gradle b/build.gradle index 5dd5baab..76235d81 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,10 @@ buildscript { - ext.kotlin_version = '1.3.0-rc-190' - ext.serialization_version = '0.8.3-rc13' - ext.kotlinx_io_version = '0.1.0-alpha-24-rc13' + ext.kotlin_version = '1.3.0' + ext.serialization_version = '0.9.0' + ext.kotlinx_io_version = '0.1.0-beta-1' + repositories { jcenter() - maven { - url = "http://dl.bintray.com/kotlin/kotlin-eap" - } } dependencies { diff --git a/dataforge-meta-io/build.gradle b/dataforge-meta-io/build.gradle index 00ecb138..242532bb 100644 --- a/dataforge-meta-io/build.gradle +++ b/dataforge-meta-io/build.gradle @@ -2,10 +2,11 @@ plugins { id 'kotlin-multiplatform' //id 'kotlinx-serialization' } + repositories { - maven { url = 'http://dl.bintray.com/kotlin/kotlin-eap' } - mavenCentral() + jcenter() } + kotlin { targets { fromPreset(presets.jvm, 'jvm') diff --git a/dataforge-meta-io/src/commonMain/kotlin/hep/dataforge/meta/io/MetaFormat.kt b/dataforge-meta-io/src/commonMain/kotlin/hep/dataforge/meta/io/MetaFormat.kt index 7fd73460..552f9532 100644 --- a/dataforge-meta-io/src/commonMain/kotlin/hep/dataforge/meta/io/MetaFormat.kt +++ b/dataforge-meta-io/src/commonMain/kotlin/hep/dataforge/meta/io/MetaFormat.kt @@ -54,7 +54,7 @@ object BinaryMetaFormat : MetaFormat { } override fun read(input: Input): Meta { - return (input.readMetaItem() as MetaItem.SingleNodeItem).node + return (input.readMetaItem() as MetaItem.NodeItem).node } private fun Output.writeChar(char: Char) = writeByte(char.toByte()) @@ -115,21 +115,14 @@ object BinaryMetaFormat : MetaFormat { writeChar('M') writeInt(meta.items.size) meta.items.forEach { (key, item) -> - writeString(key) + writeString(key.toString()) when (item) { is MetaItem.ValueItem -> { writeValue(item.value) } - is MetaItem.SingleNodeItem -> { + is MetaItem.NodeItem -> { writeMeta(item.node) } - is MetaItem.MultiNodeItem -> { - writeChar('#') - writeInt(item.nodes.size) - item.nodes.forEach { - writeMeta(it) - } - } } } } @@ -165,12 +158,7 @@ object BinaryMetaFormat : MetaFormat { set(name, item) } } - MetaItem.SingleNodeItem(meta) - } - '#' -> { - val length = readInt() - val nodes = (1..length).map { (readMetaItem() as MetaItem.SingleNodeItem).node } - MetaItem.MultiNodeItem(nodes) + MetaItem.NodeItem(meta) } else -> error("Unknown serialization key character: $keyChar") } diff --git a/dataforge-meta-io/src/jsMain/kotlin/hep/dataforge/meta/io/JSMeta.kt b/dataforge-meta-io/src/jsMain/kotlin/hep/dataforge/meta/io/JSMeta.kt index 75d0136f..3efa97ee 100644 --- a/dataforge-meta-io/src/jsMain/kotlin/hep/dataforge/meta/io/JSMeta.kt +++ b/dataforge-meta-io/src/jsMain/kotlin/hep/dataforge/meta/io/JSMeta.kt @@ -3,13 +3,14 @@ package hep.dataforge.meta.io import hep.dataforge.meta.Meta import hep.dataforge.meta.MetaItem import hep.dataforge.meta.Value +import hep.dataforge.names.NameToken /** * Represent any js object as meta */ class JSMeta(val obj: Any) : Meta { - override val items: Map> - get() = listKeys(obj).associateWith { convert(js("obj[it]")) } + override val items: Map> + get() = listKeys(obj).map { NameToken(it) }.associateWith { convert(js("obj[it]")) } private fun listKeys(obj: Any): List = js("Object").keys(obj) as List @@ -22,15 +23,9 @@ class JSMeta(val obj: Any) : Meta { null, isPrimitive(obj), is Number, is String, is Boolean -> MetaItem.ValueItem(Value.of(obj)) isList(obj) -> { val list = obj as List<*> - //if first value is primitive, treat as value - if (isPrimitive(list.first())) { - MetaItem.ValueItem(Value.of(list)) - } else { - //else treat as meta list - MetaItem.MultiNodeItem(list.map { JSMeta(it!!) }) - } + MetaItem.ValueItem(Value.of(list)) } - else -> MetaItem.SingleNodeItem(JSMeta(obj)) + else -> MetaItem.NodeItem(JSMeta(obj)) } } } \ No newline at end of file diff --git a/dataforge-meta-io/src/jvmMain/kotlin/hep/dataforge/meta/io/JSONMetaFormat.kt b/dataforge-meta-io/src/jvmMain/kotlin/hep/dataforge/meta/io/JSONMetaFormat.kt index f3bff93c..e4ac27b9 100644 --- a/dataforge-meta-io/src/jvmMain/kotlin/hep/dataforge/meta/io/JSONMetaFormat.kt +++ b/dataforge-meta-io/src/jvmMain/kotlin/hep/dataforge/meta/io/JSONMetaFormat.kt @@ -34,13 +34,8 @@ private fun Meta.toJson(): JsonObject { val builder = JsonObject() items.forEach { name, item -> when (item) { - is MetaItem.ValueItem -> builder[name] = item.value.toJson() - is MetaItem.SingleNodeItem -> builder[name] = item.node.toJson() - is MetaItem.MultiNodeItem -> { - val array = JsonArray() - item.nodes.forEach { array.add(it.toJson()) } - builder[name] = array - } + is MetaItem.ValueItem -> builder[name.toString()] = item.value.toJson() + is MetaItem.NodeItem -> builder[name.toString()] = item.node.toJson() } } return builder diff --git a/dataforge-meta/build.gradle b/dataforge-meta/build.gradle index f37628a2..8d57006e 100644 --- a/dataforge-meta/build.gradle +++ b/dataforge-meta/build.gradle @@ -1,10 +1,11 @@ plugins { id 'kotlin-multiplatform' } + repositories { - maven { url = 'http://dl.bintray.com/kotlin/kotlin-eap' } - mavenCentral() + jcenter() } + kotlin { targets { fromPreset(presets.jvm, 'jvm') diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Config.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Config.kt index 1f53ba89..1caef790 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Config.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Config.kt @@ -22,8 +22,7 @@ fun Meta.toConfig(): Config = this as? Config ?: Config().also { builder -> val item = entry.value builder[entry.key] = when (item) { is MetaItem.ValueItem -> MetaItem.ValueItem(item.value) - is MetaItem.SingleNodeItem -> MetaItem.SingleNodeItem(item.node.toConfig()) - is MetaItem.MultiNodeItem -> MetaItem.MultiNodeItem(item.nodes.map { it.toConfig() }) + is MetaItem.NodeItem -> MetaItem.NodeItem(item.node.toConfig()) } } } diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Laminate.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Laminate.kt new file mode 100644 index 00000000..295f825b --- /dev/null +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Laminate.kt @@ -0,0 +1,72 @@ +package hep.dataforge.meta + +import hep.dataforge.names.NameToken + +/** + * A meta laminate consisting of multiple immutable meta layers. For mutable front layer, use [StyledConfig]. + * + * + */ +class Laminate(val layers: List) : Meta { + + override val items: Map> + get() = layers.map { it.items.keys }.flatten().associateWith { key -> + layers.asSequence().map { it.items[key] }.filterNotNull().let(replaceRule) + } + + /** + * Generate sealed meta using [mergeRule] + */ + fun merge(): SealedMeta { + val items = layers.map { it.items.keys }.flatten().associateWith { key -> + layers.asSequence().map { it.items[key] }.filterNotNull().merge() + } + return SealedMeta(items) + } + + companion object { + + /** + * The default rule which always uses the first found item in sequence alongside with its children. + * + * TODO add picture + */ + val replaceRule: (Sequence>) -> MetaItem = { it.first().seal() } + + private fun Sequence>.merge(): MetaItem { + return when { + all { it is MetaItem.ValueItem } -> //If all items are values, take first + first().seal() + all { it is MetaItem.NodeItem } -> { + //list nodes in item + val nodes = map { it.node } + //represent as key->value entries + val entries = nodes.flatMap { it.items.entries.asSequence() } + //group by keys + val groups = entries.groupBy { it.key } + // recursively apply the rule + val items = groups.mapValues { entry -> + entry.value.asSequence().map { it.value }.merge() + } + MetaItem.NodeItem(SealedMeta(items)) + + } + else -> map { + when (it) { + is MetaItem.ValueItem -> MetaItem.NodeItem(buildMeta { Meta.VALUE_KEY to it.value }) + is MetaItem.NodeItem -> it + } + }.merge() + } + } + + + /** + * The values a replaced but meta children are joined + * TODO add picture + */ + val mergeRule: (Sequence>) -> MetaItem = { it.merge() } + } +} + +//TODO add custom rules for Laminate merge diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt index 88495f4e..f27db651 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt @@ -1,47 +1,57 @@ package hep.dataforge.meta +import hep.dataforge.meta.Meta.Companion.VALUE_KEY +import hep.dataforge.meta.MetaItem.NodeItem +import hep.dataforge.meta.MetaItem.ValueItem import hep.dataforge.names.Name +import hep.dataforge.names.NameToken import hep.dataforge.names.toName /** * A member of the meta tree. Could be represented as one of following: - * * a value - * * a single node - * * a list of nodes + * * a [ValueItem] (leaf) + * * a [NodeItem] (node) */ sealed class MetaItem { data class ValueItem(val value: Value) : MetaItem() - data class SingleNodeItem(val node: M) : MetaItem() - data class MultiNodeItem(val nodes: List) : MetaItem() -} - -operator fun List.get(query: String): M? { - return if (query.isEmpty()) { - first() - } else { - //TODO add custom key queries - get(query.toInt()) - } + data class NodeItem(val node: M) : MetaItem() } /** * Generic meta tree representation. Elements are [MetaItem] objects that could be represented by three different entities: * * [MetaItem.ValueItem] (leaf) - * * [MetaItem.SingleNodeItem] single node - * * [MetaItem.MultiNodeItem] multi-value node + * * [MetaItem.NodeItem] single node + * + * * Same name siblings are supported via elements with the same [Name] but different queries */ interface Meta { - val items: Map> -} + val items: Map> -operator fun Meta.get(name: Name): MetaItem? { - return when (name.length) { - 0 -> error("Can't resolve element from empty name") - 1 -> items[name.first()!!.body] - else -> name.first()!!.let { token -> items[token.body]?.nodes?.get(token.query) }?.get(name.cutFirst()) + companion object { + /** + * A key for single value node + */ + const val VALUE_KEY = "@value" } } +/** + * Fast [String]-based accessor for item map + */ +operator fun Map.get(body: String, query: String = ""): T? = get(NameToken(body, query)) + +operator fun Meta.get(name: Name): MetaItem? { + return name.first()?.let { token -> + val tail = name.cutFirst() + when (tail.length) { + 0 -> items[token] + else -> items[token]?.node?.get(tail) + } + } +} + +operator fun Meta.get(token: NameToken): MetaItem? = items[token] + //TODO create Java helper for meta operations operator fun Meta.get(key: String): MetaItem? = get(key.toName()) @@ -49,13 +59,15 @@ operator fun Meta.get(key: String): MetaItem? = get(key.toName()) * A meta node that ensures that all of its descendants has at least the same type */ abstract class MetaNode> : Meta { - abstract override val items: Map> + abstract override val items: Map> operator fun get(name: Name): MetaItem? { - return when (name.length) { - 0 -> error("Can't resolve element from empty name") - 1 -> items[name.first()!!.body] - else -> name.first()!!.let { token -> items[token.body]?.nodes?.get(token.query) }?.get(name.cutFirst()) + return name.first()?.let { token -> + val tail = name.cutFirst() + when (tail.length) { + 0 -> items[token] + else -> items[token]?.node?.get(tail) + } } } @@ -78,34 +90,19 @@ abstract class MetaNode> : Meta { * * If the argument is possibly mutable node, it is copied on creation */ -class SealedMeta internal constructor(override val items: Map>) : MetaNode() { - - companion object { - fun seal(meta: Meta): SealedMeta { - val items = if (meta is SealedMeta) { - meta.items - } else { - meta.items.mapValues { entry -> - val item = entry.value - when (item) { - is MetaItem.ValueItem -> MetaItem.ValueItem(item.value) - is MetaItem.SingleNodeItem -> MetaItem.SingleNodeItem(seal(item.node)) - is MetaItem.MultiNodeItem -> MetaItem.MultiNodeItem(item.nodes.map { seal(it) }) - } - } - } - return SealedMeta(items) - } - } -} - +class SealedMeta internal constructor(override val items: Map>) : MetaNode() /** * Generate sealed node from [this]. If it is already sealed return it as is */ -fun Meta.seal(): SealedMeta = this as? SealedMeta ?: SealedMeta.seal(this) +fun Meta.seal(): SealedMeta = this as? SealedMeta ?: SealedMeta(items.mapValues { entry -> entry.value.seal() }) + +fun MetaItem<*>.seal(): MetaItem = when (this) { + is MetaItem.ValueItem -> MetaItem.ValueItem(value) + is MetaItem.NodeItem -> MetaItem.NodeItem(node.seal()) +} object EmptyMeta : Meta { - override val items: Map> = emptyMap() + override val items: Map> = emptyMap() } /** @@ -113,40 +110,23 @@ object EmptyMeta : Meta { */ val MetaItem<*>.value - get() = (this as? MetaItem.ValueItem)?.value ?: error("Trying to interpret node meta item as value item") + get() = (this as? MetaItem.ValueItem)?.value + ?: (this.node[VALUE_KEY] as? MetaItem.ValueItem)?.value + ?: error("Trying to interpret node meta item as value item") val MetaItem<*>.string get() = value.string val MetaItem<*>.boolean get() = value.boolean val MetaItem<*>.number get() = value.number val MetaItem<*>.double get() = number.toDouble() val MetaItem<*>.int get() = number.toInt() val MetaItem<*>.long get() = number.toLong() +val MetaItem<*>.short get() = number.toShort() val MetaItem.node: M get() = when (this) { is MetaItem.ValueItem -> error("Trying to interpret value meta item as node item") - is MetaItem.SingleNodeItem -> node - is MetaItem.MultiNodeItem -> nodes.first() + is MetaItem.NodeItem -> node } -/** - * Utility method to access item content as list of nodes. - * Returns empty list if it is value item. - */ -val MetaItem.nodes: List - get() = when (this) { - is MetaItem.ValueItem -> emptyList()//error("Trying to interpret value meta item as node item") - is MetaItem.SingleNodeItem -> listOf(node) - is MetaItem.MultiNodeItem -> nodes - } - -fun MetaItem.indexOf(meta: M): Int { - return when (this) { - is MetaItem.ValueItem -> -1 - is MetaItem.SingleNodeItem -> if (node == meta) 0 else -1 - is MetaItem.MultiNodeItem -> nodes.indexOf(meta) - } -} - /** * Generic meta-holder object */ diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaBuilder.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaBuilder.kt index 647e560d..eb071ee7 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaBuilder.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaBuilder.kt @@ -37,9 +37,8 @@ fun Meta.builder(): MetaBuilder { items.mapValues { entry -> val item = entry.value builder[entry.key] = when (item) { - is MetaItem.ValueItem -> MetaItem.ValueItem(item.value) - is MetaItem.SingleNodeItem -> MetaItem.SingleNodeItem(item.node.builder()) - is MetaItem.MultiNodeItem -> MetaItem.MultiNodeItem(item.nodes.map { it.builder() }) + is MetaItem.ValueItem -> MetaItem.ValueItem(item.value) + is MetaItem.NodeItem -> MetaItem.NodeItem(item.node.builder()) } } } diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMetaNode.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMetaNode.kt index 4c7b40a4..324194b0 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMetaNode.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMetaNode.kt @@ -1,6 +1,7 @@ package hep.dataforge.meta import hep.dataforge.names.Name +import hep.dataforge.names.NameToken import hep.dataforge.names.plus import hep.dataforge.names.toName @@ -10,14 +11,16 @@ class MetaListener(val owner: Any? = null, val action: (name: Name, oldItem: Met interface MutableMeta> : Meta { - override val items: Map> + override val items: Map> operator fun set(name: Name, item: MetaItem?) fun onChange(owner: Any? = null, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit) fun removeListener(owner: Any) } /** - * A mutable meta node with attachable change listener + * A mutable meta node with attachable change listener. + * + * Changes in Meta are not thread safe. */ abstract class MutableMetaNode> : MetaNode(), MutableMeta { private val listeners = HashSet() @@ -36,26 +39,24 @@ abstract class MutableMetaNode> : MetaNode(), MutableM listeners.removeAll { it.owner === owner } } - private val _items: MutableMap> = HashMap() + private val _items: MutableMap> = HashMap() - override val items: Map> + override val items: Map> get() = _items protected fun itemChanged(name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) { listeners.forEach { it(name, oldItem, newItem) } } - protected open fun replaceItem(key: String, oldItem: MetaItem?, newItem: MetaItem?) { + protected open fun replaceItem(key: NameToken, oldItem: MetaItem?, newItem: MetaItem?) { if (newItem == null) { _items.remove(key) - oldItem?.nodes?.forEach { - it.removeListener(this) - } + oldItem?.node?.removeListener(this) } else { _items[key] = newItem - newItem.nodes.forEach { - it.onChange(this) { name, oldItem, newItem -> - itemChanged(key.toName() + name, oldItem, newItem) + if(newItem is MetaItem.NodeItem) { + newItem.node.onChange(this) { name, oldChild, newChild -> + itemChanged(key + name, oldChild, newChild) } } } @@ -79,14 +80,13 @@ abstract class MutableMetaNode> : MetaNode(), MutableM 0 -> error("Can't set meta item for empty name") 1 -> { val token = name.first()!! - if (token.hasQuery()) TODO("Queries are not supported in set operations on meta") - replaceItem(token.body, get(name), item) + replaceItem(token, get(name), item) } else -> { val token = name.first()!! //get existing or create new node. Query is ignored for new node - val child = this.items[token.body]?.nodes?.get(token.query) - ?: empty().also { this[token.body.toName()] = MetaItem.SingleNodeItem(it) } + val child = this.items[token]?.node + ?: empty().also { this[token.body.toName()] = MetaItem.NodeItem(it) } child[name.cutFirst()] = item } } @@ -99,13 +99,11 @@ fun > M.remove(name: Name) = set(name, null) fun > M.remove(name: String) = remove(name.toName()) operator fun > M.set(name: Name, value: Value) = set(name, MetaItem.ValueItem(value)) -operator fun > M.set(name: Name, meta: Meta) = set(name, MetaItem.SingleNodeItem(wrap(name, meta))) -operator fun > M.set(name: Name, metas: List) = set(name, MetaItem.MultiNodeItem(metas.map { wrap(name, it) })) - +operator fun > M.set(name: Name, meta: Meta) = set(name, MetaItem.NodeItem(wrap(name, meta))) operator fun > M.set(name: String, item: MetaItem) = set(name.toName(), item) operator fun > M.set(name: String, value: Value) = set(name.toName(), MetaItem.ValueItem(value)) operator fun > M.set(name: String, meta: Meta) = set(name.toName(), meta) -operator fun > M.set(name: String, metas: List) = set(name.toName(), metas) +operator fun > M.set(token: NameToken, item: MetaItem?) = set(token.toName(), item) /** @@ -129,19 +127,23 @@ fun > M.update(meta: Meta) { meta.items.forEach { entry -> val value = entry.value when (value) { - is MetaItem.ValueItem -> this[entry.key] = value.value - is MetaItem.SingleNodeItem -> (this[entry.key] as? MetaItem.SingleNodeItem) - ?.node?.update(value.node) ?: kotlin.run { this[entry.key] = value.node } - is MetaItem.MultiNodeItem -> { - val existing = this[entry.key] - if (existing is MetaItem.MultiNodeItem && existing.nodes.size == value.nodes.size) { - existing.nodes.forEachIndexed { index, m -> - m.update(value.nodes[index]) - } - } else { - this[entry.key] = value.nodes - } - } + is MetaItem.ValueItem -> this[entry.key.toName()] = value.value + is MetaItem.NodeItem -> (this[entry.key.toName()] as? MetaItem.NodeItem)?.node?.update(value.node) + ?: run { this[entry.key.toName()] = value.node } } } -} \ No newline at end of file +} + +// Same name siblings generation + +fun > M.setIndexed(name: Name, metas: Iterable, queryFactory: (Int) -> String = { it.toString() }) { + val tokens = name.tokens.toMutableList() + val last = tokens.last() + metas.forEachIndexed { index, meta -> + val indexedToken = NameToken(last.body, last.query + queryFactory(index)) + tokens[tokens.lastIndex] = indexedToken + set(Name(tokens), meta) + } +} + +operator fun > M.set(name: Name, metas: Iterable) = setIndexed(name, metas) diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Specification.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Specification.kt index c44763dd..132fba06 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Specification.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Specification.kt @@ -4,7 +4,7 @@ package hep.dataforge.meta * Marker interface for specifications */ interface Specification: Configurable{ - operator fun get(name: String): MetaItem? = config.get(name) + operator fun get(name: String): MetaItem? = config[name] } /** diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Styleable.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Styleable.kt index be8465e2..915ddc89 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Styleable.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Styleable.kt @@ -1,6 +1,7 @@ package hep.dataforge.meta import hep.dataforge.names.Name +import hep.dataforge.names.NameToken import hep.dataforge.names.toName /** @@ -27,12 +28,11 @@ class StyledConfig(val config: Config, style: Meta = EmptyMeta) : Config() { when (item) { null -> config.remove(name) is MetaItem.ValueItem -> config[name] = item.value - is MetaItem.SingleNodeItem -> config[name] = item.node - is MetaItem.MultiNodeItem -> config[name] = item.nodes + is MetaItem.NodeItem -> config[name] = item.node } } - override val items: Map> + override val items: Map> get() = (config.items.keys + style.items.keys).associate { key -> val value = config.items[key] val styleValue = style[key] @@ -40,16 +40,12 @@ class StyledConfig(val config: Config, style: Meta = EmptyMeta) : Config() { null -> when (styleValue) { null -> error("Should be unreachable") is MetaItem.ValueItem -> MetaItem.ValueItem(styleValue.value) - is MetaItem.SingleNodeItem -> MetaItem.SingleNodeItem(StyledConfig(config.empty(), styleValue.node)) - is MetaItem.MultiNodeItem -> MetaItem.MultiNodeItem(styleValue.nodes.map { StyledConfig(config.empty(), it) }) + is MetaItem.NodeItem -> MetaItem.NodeItem(StyledConfig(config.empty(), styleValue.node)) } is MetaItem.ValueItem -> MetaItem.ValueItem(value.value) - is MetaItem.SingleNodeItem -> MetaItem.SingleNodeItem( + is MetaItem.NodeItem -> MetaItem.NodeItem( StyledConfig(value.node, styleValue?.node ?: EmptyMeta) ) - is MetaItem.MultiNodeItem -> MetaItem.MultiNodeItem(value.nodes.map { - StyledConfig(it, styleValue?.node ?: EmptyMeta) - }) } key to item } diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/names/Name.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/names/Name.kt index 71c61379..98c7733b 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/names/Name.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/names/Name.kt @@ -58,7 +58,7 @@ class Name internal constructor(val tokens: List) { * Following symbols are prohibited in name tokens: `{}.:\`. * A name token could have appendix in square brackets called *query* */ -data class NameToken internal constructor(val body: String, val query: String) { +data class NameToken(val body: String, val query: String = "") { init { if (body.isEmpty()) error("Syntax error: Name token body is empty") @@ -108,6 +108,8 @@ fun String.toName(): Name { return Name(tokens.toList()) } +operator fun NameToken.plus(other: Name): Name = Name(listOf(this) + other.tokens) + operator fun Name.plus(other: Name): Name = Name(this.tokens + other.tokens) operator fun Name.plus(other: String): Name = this + other.toName() diff --git a/settings.gradle b/settings.gradle index f7aab5b8..71f46856 100644 --- a/settings.gradle +++ b/settings.gradle @@ -17,7 +17,6 @@ pluginManagement { } repositories { - maven { url = 'http://dl.bintray.com/kotlin/kotlin-eap' } mavenCentral() maven { url = 'https://plugins.gradle.org/m2/' } }