yaml: adding generic parse-as-invokable

This commit is contained in:
Minjae Song
2018-12-10 04:15:57 +09:00
parent 06c6c68dba
commit 3d68ae2f01
2 changed files with 87 additions and 0 deletions

View File

@@ -106,6 +106,61 @@ inline class Yaml(val text: String) {
return root
}
fun parseAsYamlInvokable(): QNDTreeNode<Pair<String, YamlInvokable?>> {
var currentIndentLevel = -1
val root = QNDTreeNode<Pair<String, YamlInvokable?>>()
var currentNode = root
val nodesStack = Stack<QNDTreeNode<Pair<String, YamlInvokable?>>>()
val validLineStartRe = Regex(""" *\- """)
nodesStack.push(currentNode)
text.split('\n') .forEach {
if (validLineStartRe.containsMatchIn(it)) { // take partial match; do the task if the text's line is valid
val indentLevel = it.countSpaces()
val it = it.trimIndent()
if (it.startsWith("- ")) { // just double check if indent-trimmed line looks valid
val nodeString = it.drop(2)
val nodeNameAndInvocation = nodeString.split(SEPARATOR)
val nodeName = nodeNameAndInvocation[0]
val nodeInvocation = loadClass(nodeNameAndInvocation[1])
val nameInvokePair = nodeName to nodeInvocation
if (indentLevel == currentIndentLevel) {
val sibling = QNDTreeNode(nameInvokePair, currentNode.parent)
currentNode.parent!!.children.add(sibling)
currentNode = sibling
}
else if (indentLevel > currentIndentLevel) {
val childNode = QNDTreeNode(nameInvokePair, currentNode)
currentNode.children.add(childNode)
nodesStack.push(currentNode)
currentNode = childNode
currentIndentLevel = indentLevel
}
else {
repeat(currentIndentLevel - indentLevel) { currentNode = nodesStack.pop() }
currentIndentLevel = indentLevel
val sibling = QNDTreeNode(nameInvokePair, currentNode.parent)
currentNode.parent!!.children.add(sibling)
currentNode = sibling
}
}
}
}
// test traverse resulting tree
/*root.traversePreorder { node, depth ->
repeat(depth + 1) { print("-") }
println("${node.data} -> ${node.parent}")
}*/
return root
}
private fun String.countSpaces(): Int {
var c = 0
while (c <= this.length) {
@@ -118,4 +173,25 @@ inline class Yaml(val text: String) {
return c
}
private fun loadClass(name: String): YamlInvokable {
val newClass = Class.forName(name)
val newClassConstructor = newClass.getConstructor(/* no args defined */)
val newClassInstance = newClassConstructor.newInstance(/* no args defined */)
return newClassInstance as YamlInvokable
}
}
/**
* A simple interface that meant to be attached with Yaml tree, so that the entry can be ```invoke()```d.
*
* Example usage in Yaml:
* ```
* - File
* - Import : net.torvald.terrarum.whatever.package.ImportFile
* ```
*
*/
interface YamlInvokable {
operator fun invoke()
}

View File

@@ -6,6 +6,7 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.AppLoader
import net.torvald.terrarum.IngameInstance
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.Yaml
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.gameactors.*
import net.torvald.terrarum.gamecontroller.KeyToggler
@@ -169,6 +170,16 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
(Terrarum.WIDTH - notifier.width) / 2, Terrarum.HEIGHT - notifier.height)
println("[BuildingMaker] Resize event")
}
private val menuYaml = Yaml("""
- File
- New
- Export
- Import
- Edit
""".trimIndent())
}