Feature: Array Iteration in NeoLang
This commit is contained in:
parent
44947f05aa
commit
04b73fc50e
@ -2,6 +2,7 @@ package io.neolang.ast.visitor
|
||||
|
||||
import io.neolang.ast.base.NeoLangAst
|
||||
import io.neolang.ast.node.*
|
||||
import io.neolang.runtime.type.NeoLangValue
|
||||
|
||||
|
||||
/**
|
||||
@ -38,11 +39,31 @@ internal object AstVisitorImpl {
|
||||
|
||||
visitorCallback.onEnterContext(arrayName)
|
||||
ast.elements.forEach {
|
||||
AstVisitorImpl.visitBlock(it.block, it.index.toString(), visitorCallback)
|
||||
AstVisitorImpl.visitArrayElementBlock(it.block, it.index, visitorCallback)
|
||||
// AstVisitorImpl.visitBlock(it.block, it.index.toString(), visitorCallback)
|
||||
}
|
||||
visitorCallback.onExitContext()
|
||||
}
|
||||
|
||||
fun visitArrayElementBlock(ast: NeoLangBlockNode, index: Int, visitorCallback: IVisitorCallback) {
|
||||
val visitingNode = ast.ast
|
||||
when (visitingNode) {
|
||||
is NeoLangGroupNode -> {
|
||||
// is a sub block, e.g.
|
||||
// block: { $blockName: {} }
|
||||
visitorCallback.onEnterContext(index.toString())
|
||||
AstVisitorImpl.visitGroup(visitingNode, visitorCallback)
|
||||
visitorCallback.onExitContext()
|
||||
}
|
||||
is NeoLangStringNode -> {
|
||||
definePrimaryData(index.toString(), visitingNode.eval(), visitorCallback)
|
||||
}
|
||||
is NeoLangNumberNode -> {
|
||||
definePrimaryData(index.toString(), visitingNode.eval(), visitorCallback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun visitBlock(ast: NeoLangBlockNode, blockName: String, visitorCallback: IVisitorCallback) {
|
||||
val visitingNode = ast.ast
|
||||
when (visitingNode) {
|
||||
@ -50,7 +71,6 @@ internal object AstVisitorImpl {
|
||||
// is a sub block, e.g.
|
||||
// block: { $blockName: {} }
|
||||
|
||||
// FIXME: Block in Array
|
||||
visitorCallback.onEnterContext(blockName)
|
||||
AstVisitorImpl.visitGroup(visitingNode, visitorCallback)
|
||||
visitorCallback.onExitContext()
|
||||
@ -61,15 +81,19 @@ internal object AstVisitorImpl {
|
||||
}
|
||||
is NeoLangStringNode -> {
|
||||
// block: { $blockName: "hello" }
|
||||
visitorCallback.getCurrentContext().defineAttribute(blockName, visitingNode.eval())
|
||||
definePrimaryData(blockName, visitingNode.eval(), visitorCallback)
|
||||
}
|
||||
is NeoLangNumberNode -> {
|
||||
// block: { $blockName: 123.456 }
|
||||
visitorCallback.getCurrentContext().defineAttribute(blockName, visitingNode.eval())
|
||||
definePrimaryData(blockName, visitingNode.eval(), visitorCallback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun definePrimaryData(name: String, value: NeoLangValue, visitorCallback: IVisitorCallback) {
|
||||
visitorCallback.getCurrentContext().defineAttribute(name, value)
|
||||
}
|
||||
|
||||
fun visitStartAst(ast: NeoLangAst, visitorCallback: IVisitorCallback) {
|
||||
when (ast) {
|
||||
is NeoLangProgramNode -> AstVisitorImpl.visitProgram(ast, visitorCallback)
|
||||
|
@ -77,6 +77,9 @@ class NeoLangParser {
|
||||
return NeoLangProgramNode.emptyNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* @param attrName Only available when group is a attribute value
|
||||
*/
|
||||
private fun group(): NeoLangGroupNode? {
|
||||
val token = currentToken ?: throw InvalidTokenException("Unexpected token: null")
|
||||
|
||||
@ -115,13 +118,11 @@ class NeoLangParser {
|
||||
private fun array(arrayName: NeoLangStringNode): NeoLangArrayNode? {
|
||||
val token = currentToken ?: throw InvalidTokenException("Unexpected token: null")
|
||||
|
||||
|
||||
// TODO: Multiple Array
|
||||
var block = blockNonArrayElement(arrayName)
|
||||
var index = 0
|
||||
|
||||
if (block != null) {
|
||||
|
||||
val elements = mutableListOf(NeoLangArrayElement(index++, block))
|
||||
|
||||
if (match(NeoLangTokenType.COMMA)) {
|
||||
@ -149,7 +150,7 @@ class NeoLangParser {
|
||||
|
||||
|
||||
/**
|
||||
* @attrName The block holder's name
|
||||
* @param attrName The block holder's name
|
||||
*/
|
||||
private fun block(attrName: NeoLangStringNode): NeoLangBlockNode? {
|
||||
val block = blockNonArrayElement(attrName)
|
||||
@ -172,7 +173,10 @@ class NeoLangParser {
|
||||
}
|
||||
}
|
||||
|
||||
private fun blockNonArrayElement(attrName: NeoLangStringNode): NeoLangBlockNode? {
|
||||
/**
|
||||
* @param attrName Only available when group is a attribute value
|
||||
*/
|
||||
private fun blockNonArrayElement(attrName: NeoLangStringNode?): NeoLangBlockNode? {
|
||||
val token = currentToken ?: throw InvalidTokenException("Unexpected token: null")
|
||||
|
||||
return when (token.tokenType) {
|
||||
|
@ -6,19 +6,32 @@ import io.neolang.runtime.type.NeoLangValue
|
||||
* @author kiva
|
||||
*/
|
||||
class NeoLangContext(val contextName: String) {
|
||||
companion object {
|
||||
private val emptyContext = NeoLangContext("<Context-Empty>")
|
||||
}
|
||||
|
||||
private val attributes = mutableMapOf<String, NeoLangValue>()
|
||||
|
||||
var parent: NeoLangContext? = null
|
||||
var children = mutableListOf<NeoLangContext>()
|
||||
|
||||
fun defineAttribute(attributeName: String, attributeValue: NeoLangValue): NeoLangContext {
|
||||
attributes[attributeName] = attributeValue
|
||||
return this
|
||||
}
|
||||
|
||||
fun getAttribute(attributeName: String): NeoLangValue {
|
||||
return attributes[attributeName] ?: NeoLangValue.UNDEFINED
|
||||
return attributes[attributeName] ?: parent?.getAttribute(attributeName) ?: NeoLangValue.UNDEFINED
|
||||
}
|
||||
|
||||
fun defineArray() {
|
||||
|
||||
fun getChild(contextName: String): NeoLangContext {
|
||||
var found: NeoLangContext? = null
|
||||
children.forEach {
|
||||
if (it.contextName == contextName) {
|
||||
found = it
|
||||
}
|
||||
}
|
||||
return found ?: emptyContext
|
||||
}
|
||||
|
||||
fun getAttributes(): Map<String, NeoLangValue> {
|
||||
|
@ -22,6 +22,9 @@ open class NeoColorScheme {
|
||||
const val COLOR_META_NAME = "name"
|
||||
const val COLOR_META_VERSION = "version"
|
||||
|
||||
val COLOR_META_PATH = arrayOf(COLOR_META_CONTEXT_NAME)
|
||||
val COLOR_PATH = arrayOf(COLOR_META_CONTEXT_NAME, COLOR_CONTEXT_NAME)
|
||||
|
||||
// const val COLOR_DIM_BLACK = 0
|
||||
// const val COLOR_DIM_RED = 1
|
||||
// const val COLOR_DIM_GREEN = 2
|
||||
@ -95,7 +98,7 @@ open class NeoColorScheme {
|
||||
backgroundColor = getColorByVisitor(visitor, "background")
|
||||
foregroundColor = getColorByVisitor(visitor, "foreground")
|
||||
cursorColor = getColorByVisitor(visitor, "cursor")
|
||||
visitor.getContext(COLOR_CONTEXT_NAME).getAttributes().forEach {
|
||||
visitor.getCurrentContext().getChild(COLOR_CONTEXT_NAME).getAttributes().forEach {
|
||||
val colorIndex = try {
|
||||
it.key.substringAfter(COLOR_PREFIX).toInt()
|
||||
} catch (e: Exception) {
|
||||
@ -114,12 +117,12 @@ open class NeoColorScheme {
|
||||
}
|
||||
|
||||
private fun getMetaByVisitor(visitor: ConfigVisitor, metaName: String): String? {
|
||||
val value = visitor.getAttribute(COLOR_META_CONTEXT_NAME, metaName)
|
||||
val value = visitor.getAttribute(COLOR_META_PATH, metaName)
|
||||
return if (value.isValid()) value.asString() else null
|
||||
}
|
||||
|
||||
private fun getColorByVisitor(visitor: ConfigVisitor, colorName: String): String? {
|
||||
val value = visitor.getAttribute(COLOR_CONTEXT_NAME, colorName)
|
||||
val value = visitor.getAttribute(COLOR_PATH, colorName)
|
||||
return if (value.isValid()) value.asString() else null
|
||||
}
|
||||
}
|
@ -3,47 +3,49 @@ package io.neoterm.frontend.config
|
||||
import io.neolang.ast.visitor.IVisitorCallback
|
||||
import io.neolang.runtime.context.NeoLangContext
|
||||
import io.neolang.runtime.type.NeoLangValue
|
||||
import java.util.*
|
||||
|
||||
class ConfigVisitor : IVisitorCallback {
|
||||
private val emptyContext = NeoLangContext("<NeoTerm-Empty-Safety>")
|
||||
private val contextStack = Stack<NeoLangContext>()
|
||||
private val definedContext = mutableListOf<NeoLangContext>()
|
||||
private var currentContext: NeoLangContext? = null
|
||||
|
||||
fun getContext(contextName: String): NeoLangContext {
|
||||
definedContext.forEach {
|
||||
if (it.contextName == contextName) {
|
||||
return it
|
||||
}
|
||||
fun getContext(contextPath: Array<String>) : NeoLangContext {
|
||||
var context = getCurrentContext()
|
||||
contextPath.forEach {
|
||||
context = context.getChild(it)
|
||||
}
|
||||
return emptyContext
|
||||
return context
|
||||
}
|
||||
|
||||
fun getAttribute(contextName: String, attrName: String): NeoLangValue {
|
||||
return getContext(contextName).getAttribute(attrName)
|
||||
fun getAttribute(contextPath: Array<String>, attrName: String) : NeoLangValue {
|
||||
return getContext(contextPath).getAttribute(attrName)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
onEnterContext("global")
|
||||
currentContext = NeoLangContext("global")
|
||||
}
|
||||
|
||||
override fun onFinish() {
|
||||
while (contextStack.isNotEmpty()) {
|
||||
onExitContext()
|
||||
var context = currentContext
|
||||
while (context != null && context.parent != null) {
|
||||
context = context.parent
|
||||
}
|
||||
this.currentContext = context
|
||||
}
|
||||
|
||||
override fun onEnterContext(contextName: String) {
|
||||
val context = NeoLangContext(contextName)
|
||||
contextStack.push(context)
|
||||
val newContext = NeoLangContext(contextName)
|
||||
newContext.parent = currentContext
|
||||
currentContext!!.children.add(newContext)
|
||||
currentContext = newContext
|
||||
}
|
||||
|
||||
override fun onExitContext() {
|
||||
val context = contextStack.pop()
|
||||
definedContext.add(context)
|
||||
val context = currentContext
|
||||
if (context != null && context.parent != null) {
|
||||
this.currentContext = context.parent
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCurrentContext(): NeoLangContext {
|
||||
return contextStack.peek()
|
||||
return currentContext!!
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package io.neoterm
|
||||
|
||||
import io.neoterm.customize.color.NeoColorScheme
|
||||
import io.neoterm.frontend.config.ConfigVisitor
|
||||
import io.neoterm.frontend.config.NeoConfigureFile
|
||||
import org.junit.Test
|
||||
@ -9,21 +10,44 @@ import java.io.File
|
||||
* @author kiva
|
||||
*/
|
||||
class ConfigureFileTest {
|
||||
private fun printAttr(visitor: ConfigVisitor, contextName: String, attrName: String) {
|
||||
println("attr [$contextName->$attrName]: ${visitor.getAttribute(contextName, attrName).asString()}")
|
||||
private fun getMetaByVisitor(visitor: ConfigVisitor, metaName: String): String? {
|
||||
val value = visitor.getAttribute(NeoColorScheme.COLOR_META_PATH, metaName)
|
||||
return if (value.isValid()) value.asString() else null
|
||||
}
|
||||
|
||||
private fun parseConfigure(filePath: String, contextName: String, attrName: String) {
|
||||
private fun getColorByVisitor(visitor: ConfigVisitor, colorName: String): String? {
|
||||
val value = visitor.getAttribute(NeoColorScheme.COLOR_PATH, colorName)
|
||||
return if (value.isValid()) value.asString() else null
|
||||
}
|
||||
|
||||
private fun parseConfigure(filePath: String): ConfigVisitor? {
|
||||
val config = NeoConfigureFile(File(filePath))
|
||||
if (config.parseConfigure()) {
|
||||
val visitor = config.getVisitor()
|
||||
printAttr(visitor, contextName, attrName)
|
||||
return visitor
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@Test
|
||||
fun colorConfigureTest() {
|
||||
val visitor = parseConfigure("NeoLang/example/color-scheme.nl")
|
||||
if (visitor != null) {
|
||||
println("colorName: ${getMetaByVisitor(visitor, NeoColorScheme.COLOR_META_NAME)}")
|
||||
println("colorVersion: ${getMetaByVisitor(visitor, NeoColorScheme.COLOR_META_VERSION)}")
|
||||
println("background: ${getColorByVisitor(visitor, "background")}")
|
||||
println("foreground: ${getColorByVisitor(visitor, "foreground")}")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun extraKeyConfigureTest() {
|
||||
parseConfigure("NeoLang/example/extra-key.nl")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun configureFileTest() {
|
||||
// parseConfigure("NeoLang/example/color-scheme.nl", "colors", "foreground")
|
||||
parseConfigure("NeoLang/example/extra-key.nl", "key", "0")
|
||||
colorConfigureTest()
|
||||
extraKeyConfigureTest()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user