Feature: Array Iteration in NeoLang

This commit is contained in:
zt515 2017-08-09 02:38:06 +08:00
parent 44947f05aa
commit 04b73fc50e
6 changed files with 110 additions and 40 deletions

View File

@ -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)

View File

@ -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) {

View File

@ -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> {

View File

@ -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
}
}

View File

@ -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!!
}
}

View File

@ -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()
}
}