Improve: NeoLang Array supports collection operations

This commit is contained in:
zt515 2017-08-09 04:27:31 +08:00
parent 5ae36672af
commit 1e50bbbafa
15 changed files with 116 additions and 46 deletions

View File

@ -1,6 +1,7 @@
extra-key: {
program: [ "vim", "vi" ]
key: [
"hello",
{
display: "Ctrl"
code: "<CTRL>"

View File

@ -1,9 +1,12 @@
package io.neolang.ast.node
import io.neolang.ast.base.NeoLangBaseNode
import io.neolang.runtime.type.NeoLangArrayElement
/**
* @author kiva
*/
class NeoLangArrayNode(val arrayNameNode: NeoLangStringNode, val elements: Array<NeoLangArrayElement>) : NeoLangBaseNode()
class NeoLangArrayNode(val arrayNameNode: NeoLangStringNode, val elements: Array<ArrayElement>) : NeoLangBaseNode() {
companion object {
class ArrayElement(val index: Int, val block: NeoLangBlockNode)
}
}

View File

@ -1,6 +1,7 @@
package io.neolang.main
import io.neolang.parser.NeoLangParser
import io.neolang.visitor.DisplayProcessVisitor
import java.io.FileInputStream
/**

View File

@ -5,7 +5,6 @@ import io.neolang.ast.NeoLangTokenType
import io.neolang.ast.NeoLangTokenValue
import io.neolang.ast.base.NeoLangAst
import io.neolang.ast.node.*
import io.neolang.runtime.type.NeoLangArrayElement
/**
* @author kiva
@ -123,7 +122,7 @@ class NeoLangParser {
var index = 0
if (block != null) {
val elements = mutableListOf(NeoLangArrayElement(index++, block))
val elements = mutableListOf(NeoLangArrayNode.Companion.ArrayElement(index++, block))
if (match(NeoLangTokenType.COMMA)) {
// More than one elements
@ -133,7 +132,7 @@ class NeoLangParser {
if (block == null) {
break
}
elements.add(NeoLangArrayElement(index++, block))
elements.add(NeoLangArrayNode.Companion.ArrayElement(index++, block))
// Meet the last element
if (!match(NeoLangTokenType.COMMA)) {

View File

@ -11,9 +11,8 @@ class NeoLangContext(val contextName: String) {
}
private val attributes = mutableMapOf<String, NeoLangValue>()
val children = mutableListOf<NeoLangContext>()
var parent: NeoLangContext? = null
var children = mutableListOf<NeoLangContext>()
fun defineAttribute(attributeName: String, attributeValue: NeoLangValue): NeoLangContext {
attributes[attributeName] = attributeValue

View File

@ -0,0 +1,59 @@
package io.neolang.runtime.type
import io.neolang.runtime.context.NeoLangContext
/**
* @author kiva
*/
class NeoLangArray private constructor(val elements: List<NeoLangArrayElement>, override val size: Int = elements.size) : Collection<NeoLangArrayElement> {
companion object {
internal class PrimaryElement(val primaryValue: NeoLangValue) : NeoLangArrayElement() {
override fun eval(): NeoLangValue {
return primaryValue
}
}
internal class BlockElement(val blockContext: NeoLangContext) : NeoLangArrayElement() {
override fun eval(key: String): NeoLangValue {
return blockContext.getAttribute(key)
}
override fun isBlock(): Boolean {
return true
}
}
fun createFromContext(context: NeoLangContext): NeoLangArray {
val elements = mutableListOf<NeoLangArrayElement>()
context.getAttributes().entries.forEach {
val index = it.key.toInt()
elements.add(index, PrimaryElement(it.value))
}
context.children.forEach {
val index = it.contextName.toInt()
elements.add(index, BlockElement(it))
}
return NeoLangArray(elements)
}
}
operator fun get(index: Int): NeoLangArrayElement {
return elements[index]
}
override fun contains(element: NeoLangArrayElement): Boolean {
return elements.contains(element)
}
override fun containsAll(elements: Collection<NeoLangArrayElement>): Boolean {
return this.elements.containsAll(elements)
}
override fun isEmpty(): Boolean {
return size == 0
}
override fun iterator(): Iterator<NeoLangArrayElement> {
return elements.iterator()
}
}

View File

@ -1,8 +1,18 @@
package io.neolang.runtime.type
import io.neolang.ast.node.NeoLangBlockNode
/**
* @author kiva
*/
class NeoLangArrayElement(val index: Int, val block: NeoLangBlockNode)
open class NeoLangArrayElement {
open fun eval(): NeoLangValue {
return NeoLangValue.UNDEFINED
}
open fun eval(key: String): NeoLangValue {
return NeoLangValue.UNDEFINED
}
open fun isBlock(): Boolean {
return false
}
}

View File

@ -1,27 +1,10 @@
package io.neolang.runtime.type
import io.neolang.ast.node.NeoLangBlockNode
/**
* @author kiva
*/
class NeoLangValue(private val rawValue: Any) {
fun asString(): String {
if (rawValue is Array<*>) {
val array = asArray()
return buildString {
append("Array [ ")
array.forEachIndexed { index, value ->
append(value.asString())
if (index != array.size - 1) {
append(", ")
}
}
append(" ]")
}
}
return rawValue.toString()
}
@ -37,17 +20,6 @@ class NeoLangValue(private val rawValue: Any) {
}
}
fun asArray(): Array<NeoLangValue> {
return castArrayOrNull(rawValue) ?: arrayOf()
}
@Suppress("UNCHECKED_CAST")
private fun castArrayOrNull(rawValue: Any): Array<NeoLangValue>? {
return if (rawValue is Array<*> && rawValue.isNotEmpty() && rawValue[0] is NeoLangValue)
rawValue as Array<NeoLangValue>
else null
}
fun isValid(): Boolean {
return this != UNDEFINED
}

View File

@ -1,7 +1,8 @@
package io.neoterm.frontend.config
package io.neolang.visitor
import io.neolang.ast.visitor.IVisitorCallback
import io.neolang.runtime.context.NeoLangContext
import io.neolang.runtime.type.NeoLangArray
import io.neolang.runtime.type.NeoLangValue
class ConfigVisitor : IVisitorCallback {
@ -19,6 +20,11 @@ class ConfigVisitor : IVisitorCallback {
return getContext(contextPath).getAttribute(attrName)
}
fun getArray(contextPath: Array<String>, arrayName: String) : NeoLangArray {
// We use NeoLangContext as arrays and array elements now
return NeoLangArray.createFromContext(getContext(contextPath).getChild(arrayName))
}
override fun onStart() {
currentContext = NeoLangContext("global")
}

View File

@ -1,4 +1,4 @@
package io.neolang.main
package io.neolang.visitor
import io.neolang.ast.visitor.IVisitorCallbackAdapter
import io.neolang.runtime.context.NeoLangContext

View File

@ -3,7 +3,7 @@ package io.neoterm.customize.color
import io.neoterm.backend.TerminalColorScheme
import io.neoterm.backend.TerminalColors
import io.neoterm.customize.config.ConfigureService
import io.neoterm.frontend.config.ConfigVisitor
import io.neolang.visitor.ConfigVisitor
import io.neoterm.frontend.logging.NLog
import io.neoterm.frontend.service.ServiceManager
import io.neoterm.view.TerminalView

View File

@ -2,7 +2,7 @@ package io.neoterm.customize.config.loader
import io.neolang.runtime.type.NeoLangValue
import io.neoterm.customize.color.NeoColorScheme
import io.neoterm.frontend.config.ConfigVisitor
import io.neolang.visitor.ConfigVisitor
import io.neoterm.frontend.config.NeoConfigureFile
import io.neoterm.frontend.logging.NLog
import java.io.File

View File

@ -2,7 +2,7 @@ package io.neoterm.customize.config.loader
import io.neoterm.customize.eks.ExtraKeyConfigParser
import io.neoterm.customize.eks.NeoExtraKey
import io.neoterm.frontend.config.ConfigVisitor
import io.neolang.visitor.ConfigVisitor
import io.neoterm.frontend.config.NeoConfigureFile
import io.neoterm.view.eks.button.TextButton
import java.io.BufferedReader

View File

@ -1,6 +1,7 @@
package io.neoterm.frontend.config
import io.neolang.parser.NeoLangParser
import io.neolang.visitor.ConfigVisitor
import io.neoterm.frontend.logging.NLog
import io.neoterm.utils.FileUtils
import java.io.File

View File

@ -2,7 +2,7 @@ package io.neoterm
import io.neoterm.customize.color.NeoColorScheme
import io.neoterm.customize.config.ConfigureService
import io.neoterm.frontend.config.ConfigVisitor
import io.neolang.visitor.ConfigVisitor
import io.neoterm.frontend.config.NeoConfigureFile
import io.neoterm.frontend.service.ServiceManager
import org.junit.Test
@ -23,7 +23,11 @@ class ConfigureFileTest {
@Test
fun colorConfigureTest() {
ServiceManager.registerService(ConfigureService::class.java)
try {
ServiceManager.registerService(ConfigureService::class.java)
} catch (ignore: Throwable) {
}
val color = NeoColorScheme()
if (color.loadConfigure(File("NeoLang/example/color-scheme.nl"))) {
println("colorName: ${color.colorName}")
@ -37,7 +41,22 @@ class ConfigureFileTest {
@Test
fun extraKeyConfigureTest() {
parseConfigure("NeoLang/example/extra-key.nl")
val visitor = parseConfigure("NeoLang/example/extra-key.nl")
if (visitor != null) {
val programs = visitor.getArray(arrayOf("extra-key"), "program")
programs.forEachIndexed { index, element ->
println("program[$index]: ${element.eval().asString()}")
}
val keys = visitor.getArray(arrayOf("extra-key"), "key")
keys.forEachIndexed { index, element ->
if (element.isBlock()) {
println("key[$index]: " +
"display: ${element.eval("display").asString()}, " +
"code: ${element.eval("code").asString()}")
}
}
}
}
@Test