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