Skip to content

Instantly share code, notes, and snippets.

@Jire
Last active January 3, 2016 12:37
Show Gist options
  • Save Jire/6ecb8315a963ec653b14 to your computer and use it in GitHub Desktop.
Save Jire/6ecb8315a963ec653b14 to your computer and use it in GitHub Desktop.
package org.jire.kton
import java.util.*
/**
* Represents an instance of KTON (Kotlin object notation).
*
* @author Thomas Nappo
*/
class KTON(private var arrCursor: Int = -1) {
private var lastCursor = arrCursor
/**
* Maps string keys with their values.
*/
private val vars = HashMap<String, Any>()
/**
* Gets the corresponding value of a key, potentially `null`.
*
* @param key The key of the value.
*/
operator fun get(key: String) = vars[formatKey(key)]
/**
* Gets the corresponding KTON body of a key.
*
* @param key The key of the body.
*/
operator fun invoke(key: String) = this[key]!! as KTON
/**
* Gets the corresponding KTON array of an index.
*
* @param index The index of the array (of declaration order).
*/
operator fun get(index: Int): KTON {
arrCursor = index
return this
}
/**
* Establishes (maps) a value to the current string in a KTON.
*/
infix fun <V : Any> String.to(value: V) {
vars[formatKey(this)] = value
}
/**
* Establishes (maps) a body to the current string in a KTON.
*
* @param body The body representing the new KTON.
*/
operator fun <O> String.invoke(body: KTON.() -> O) = to(kton(body))
operator fun <O> (() -> O).unaryPlus() {
if (arrCursor >= 0) throw UnsupportedOperationException("Multi-dimension arrays not supported!")
arrCursor = lastCursor + 1
this()
lastCursor = arrCursor
arrCursor = -1
}
private fun formatKey(key: String) = if (arrCursor < 0) key else "[$arrCursor][$key]"
}
/**
* Creates a KTON using the supplied body.
*
* @param body The body of the KTON used to declare more KTONs or values.
*/
inline fun <O> kton(body: KTON.() -> O): KTON {
val kton = KTON()
kton.body()
return kton
}
fun main(args: Array<String>) {
val menu = kton {
"id" to "file"
"value" to "File"
"popup" {
"menuitem" {
+{ "value" to "New"; "onclick" to "CreateNewDoc()" }
+{ "value" to "Open"; "onclick" to "OpenDoc()" }
+{ "value" to "Close"; "onclick" to "CloseDoc()" }
}
}
}
// Value access through get operator:
val id = menu["id"] // "file"
val value = menu["value"] // "File"
// Body access through invoke operator:
val popup = menu("popup")
val menuitems = popup("menuitem")
// Array access through get operator specifying index:
val newValue = menuitems[0]["value"] // "New"
val open = menuitems[1]
val openValue = open["value"] // "Open"
val closeOnClick = menuitems[2]["onclick"] // "CloseDoc()"
assert(id == "File")
assert(value == "File")
assert(newValue == "New")
assert(openValue == "Open")
assert(closeOnClick == "CloseDoc()")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment