MISC: even more flatten!

This commit is contained in:
imkiva 2021-05-08 19:04:01 +08:00 committed by Kiva Oyama
parent 56167cce5d
commit 236072395c
46 changed files with 565 additions and 728 deletions

View File

@ -1,6 +0,0 @@
package io.neolang.ast
/**
* @author kiva
*/
class NeoLangEOFToken : NeoLangToken(NeoLangTokenType.EOF, NeoLangTokenValue.EOF)

View File

@ -1,13 +0,0 @@
package io.neolang.ast
/**
* @author kiva
*/
open class NeoLangToken(val tokenType: NeoLangTokenType, val tokenValue: NeoLangTokenValue) {
var lineNumber = 0
override fun toString(): String {
return "Token { tokenType: $tokenType, tokenValue: $tokenValue };"
}
}

View File

@ -1,19 +0,0 @@
package io.neolang.ast
/**
* @author kiva
*/
enum class NeoLangTokenType {
NUMBER,
ID,
STRING,
BRACKET_START,
BRACKET_END,
ARRAY_START,
ARRAY_END,
COLON,
COMMA,
EOL,
EOF,
}

View File

@ -1,12 +0,0 @@
package io.neolang.ast.base
import io.neolang.ast.visitor.VisitorFactory
/**
* @author kiva
*/
open class NeoLangAst {
fun visit(): VisitorFactory {
return VisitorFactory(this)
}
}

View File

@ -1,3 +0,0 @@
package io.neolang.ast.base
open class NeoLangBaseNode : NeoLangAst()

View File

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

View File

@ -1,12 +0,0 @@
package io.neolang.ast.node
import io.neolang.ast.base.NeoLangBaseNode
/**
* @author kiva
*/
open class NeoLangAstBasedNode(val ast: NeoLangBaseNode) : NeoLangBaseNode() {
override fun toString(): String {
return "${javaClass.simpleName} { ast: $ast }"
}
}

View File

@ -1,13 +0,0 @@
package io.neolang.ast.node
import io.neolang.ast.base.NeoLangBaseNode
/**
* @author kiva
*/
class NeoLangAttributeNode(val stringNode: NeoLangStringNode, val blockNode: NeoLangBlockNode) : NeoLangBaseNode() {
override fun toString(): String {
return "NeoLangAttributeNode { stringNode: $stringNode, block: $blockNode }"
}
}

View File

@ -1,14 +0,0 @@
package io.neolang.ast.node
import io.neolang.ast.base.NeoLangBaseNode
/**
* @author kiva
*/
class NeoLangBlockNode(blockElement: NeoLangBaseNode) : NeoLangAstBasedNode(blockElement) {
companion object {
fun emptyNode(): NeoLangBlockNode {
return NeoLangBlockNode(NeoLangDummyNode())
}
}
}

View File

@ -1,8 +0,0 @@
package io.neolang.ast.node
import io.neolang.ast.base.NeoLangBaseNode
/**
* @author kiva
*/
class NeoLangDummyNode : NeoLangBaseNode()

View File

@ -1,19 +0,0 @@
package io.neolang.ast.node
import io.neolang.ast.base.NeoLangBaseNode
/**
* @author kiva
*/
class NeoLangGroupNode(val attributes: Array<NeoLangAttributeNode>) : NeoLangBaseNode() {
override fun toString(): String {
return "NeoLangGroupNode { attrs: $attributes }"
}
companion object {
fun emptyNode(): NeoLangGroupNode {
return NeoLangGroupNode(arrayOf())
}
}
}

View File

@ -1,8 +0,0 @@
package io.neolang.ast.node
import io.neolang.ast.NeoLangToken
/**
* @author kiva
*/
class NeoLangNumberNode(token: NeoLangToken) : NeoLangTokenBasedNode(token)

View File

@ -1,21 +0,0 @@
package io.neolang.ast.node
import io.neolang.ast.base.NeoLangBaseNode
/**
* @author kiva
*/
class NeoLangProgramNode(val groups: List<NeoLangGroupNode>) : NeoLangBaseNode() {
override fun toString(): String {
return "NeoLangProgramNode { groups: $groups }"
}
companion object {
fun emptyNode(): NeoLangProgramNode {
return NeoLangProgramNode(listOf())
}
}
}

View File

@ -1,8 +0,0 @@
package io.neolang.ast.node
import io.neolang.ast.NeoLangToken
/**
* @author kiva
*/
class NeoLangStringNode(token: NeoLangToken) : NeoLangTokenBasedNode(token)

View File

@ -1,18 +0,0 @@
package io.neolang.ast.node
import io.neolang.ast.NeoLangToken
import io.neolang.ast.base.NeoLangBaseNode
import io.neolang.runtime.type.NeoLangValue
/**
* @author kiva
*/
open class NeoLangTokenBasedNode(val token: NeoLangToken) : NeoLangBaseNode() {
override fun toString(): String {
return "${javaClass.simpleName} { token: $token }"
}
fun eval(): NeoLangValue {
return token.tokenValue.value
}
}

View File

@ -1,17 +0,0 @@
package io.neolang.ast.visitor
import io.neolang.ast.base.NeoLangAst
/**
* @author kiva
*/
class AstVisitor(private val ast: NeoLangAst, private val visitorCallback: IVisitorCallback) {
fun start() {
AstVisitorImpl.visitStartAst(ast, visitorCallback)
}
@Suppress("UNCHECKED_CAST")
fun <T : IVisitorCallback> getCallback(): T {
return visitorCallback as T
}
}

View File

@ -1,18 +0,0 @@
package io.neolang.ast.visitor
import io.neolang.runtime.context.NeoLangContext
/**
* @author kiva
*/
interface IVisitorCallback {
fun onStart()
fun onFinish()
fun onEnterContext(contextName: String)
fun onExitContext()
fun getCurrentContext(): NeoLangContext
}

View File

@ -1,24 +0,0 @@
package io.neolang.ast.visitor
import io.neolang.runtime.context.NeoLangContext
/**
* @author kiva
*/
open class IVisitorCallbackAdapter : IVisitorCallback {
override fun onStart() {
}
override fun onFinish() {
}
override fun onEnterContext(contextName: String) {
}
override fun onExitContext() {
}
override fun getCurrentContext(): NeoLangContext {
throw RuntimeException("getCurrentContext() not supported in this IVisitorCallback!")
}
}

View File

@ -1,18 +0,0 @@
package io.neolang.ast.visitor
import io.neolang.ast.base.NeoLangAst
/**
* @author kiva
*/
class VisitorFactory(private val ast: NeoLangAst) {
fun getVisitor(callbackInterface: Class<out IVisitorCallback>): AstVisitor? {
try {
return AstVisitor(ast, callbackInterface.newInstance())
} catch (e: Exception) {
return null
}
}
}

View File

@ -1,18 +1,21 @@
package io.neolang.ast.visitor package io.neolang.frontend
import io.neolang.ast.base.NeoLangAst
import io.neolang.ast.node.*
import io.neolang.runtime.type.NeoLangValue
import io.neolang.runtime.NeoLangContext
import io.neolang.runtime.NeoLangValue
/** /**
* grammar: [ * @author kiva
* program: group (group)*
* group: attribute (attribute)*
* attribute: ID COLON block
* block: STRING | NUMBER | (BRACKET_START [group|] BRACKET_END) | (ARRAY_START [block(<,block>)+|] ARRAY_END)
* ]
*/ */
class AstVisitor(private val ast: NeoLangAst, private val visitorCallback: IVisitorCallback) {
fun start() {
AstVisitorImpl.visitStartAst(ast, visitorCallback)
}
@Suppress("UNCHECKED_CAST")
fun <T : IVisitorCallback> getCallback(): T {
return visitorCallback as T
}
}
/** /**
* @author kiva * @author kiva
@ -102,3 +105,54 @@ internal object AstVisitorImpl {
} }
} }
} }
/**
* @author kiva
*/
interface IVisitorCallback {
fun onStart()
fun onFinish()
fun onEnterContext(contextName: String)
fun onExitContext()
fun getCurrentContext(): NeoLangContext
}
/**
* @author kiva
*/
open class IVisitorCallbackAdapter : IVisitorCallback {
override fun onStart() {
}
override fun onFinish() {
}
override fun onEnterContext(contextName: String) {
}
override fun onExitContext() {
}
override fun getCurrentContext(): NeoLangContext {
throw RuntimeException("getCurrentContext() not supported in this IVisitorCallback!")
}
}
/**
* @author kiva
*/
class VisitorFactory(private val ast: NeoLangAst) {
fun getVisitor(callbackInterface: Class<out IVisitorCallback>): AstVisitor? {
try {
return AstVisitor(ast, callbackInterface.newInstance())
} catch (e: Exception) {
return null
}
}
}

View File

@ -1,18 +1,4 @@
package io.neolang.parser package io.neolang.frontend
import io.neolang.ast.NeoLangEOFToken
import io.neolang.ast.NeoLangToken
import io.neolang.ast.NeoLangTokenType
import io.neolang.ast.NeoLangTokenValue
/**
* grammar: [
* program: group (group)*
* group: attribute (attribute)*
* attribute: ID COLON block
* block: STRING | NUMBER | (BRACKET_START [group|] BRACKET_END) | (ARRAY_START [block(<,block>)+|] ARRAY_END)
* ]
*/
/** /**
* @author kiva * @author kiva
@ -201,9 +187,7 @@ class NeoLangLexer {
var value = numberValue var value = numberValue
var loop = moveToNextChar() // skip 'x' or 'X' var loop = moveToNextChar() // skip 'x' or 'X'
while (loop && (currentChar.isHexNumber())) { while (loop && (currentChar.isHexNumber())) {
value *= 16 value *= 16 + (currentChar.toInt().and(15)) + if (currentChar >= 'A') 9 else 0
+(currentChar.toInt().and(15))
+if (currentChar >= 'A') 9 else 0
loop = moveToNextChar() loop = moveToNextChar()
} }
return value return value
@ -270,3 +254,208 @@ class NeoLangLexer {
|| this in ('A'..'F') || this in ('A'..'F')
} }
} }
/**
* @author kiva
*/
class NeoLangParser {
private val lexer = NeoLangLexer()
private var tokens = mutableListOf<NeoLangToken>()
private var currentPosition: Int = 0
private var currentToken: NeoLangToken? = null
fun setInputSource(programCode: String?) {
lexer.setInputSource(programCode)
}
fun parse(): NeoLangAst {
return updateParserStatus(lexer.lex()) ?: throw ParseException("AST is null")
}
private fun updateParserStatus(tokens: List<NeoLangToken>): NeoLangAst? {
if (tokens.isEmpty()) {
// Allow empty program
return NeoLangProgramNode.emptyNode()
}
this.tokens.clear()
this.tokens.addAll(tokens)
currentPosition = 0
currentToken = tokens[currentPosition]
return program()
}
private fun match(tokenType: NeoLangTokenType, errorThrow: Boolean = false): Boolean {
val currentToken = this.currentToken ?: throw InvalidTokenException("Unexpected token: null")
if (currentToken.tokenType === tokenType) {
currentPosition++
if (currentPosition >= tokens.size) {
this.currentToken = NeoLangToken(NeoLangTokenType.EOF, NeoLangTokenValue.EOF)
} else {
this.currentToken = tokens[currentPosition]
}
return true
} else if (errorThrow) {
throw InvalidTokenException(
"Unexpected token `${currentToken.tokenValue}' typed " +
"`${currentToken.tokenType}' near line ${currentToken.lineNumber}, " +
"expected $tokenType",
)
}
return false
}
private fun program(): NeoLangProgramNode {
val token = currentToken
var group = group()
if (group != null) {
val groups = mutableListOf(group)
while (token?.tokenType !== NeoLangTokenType.EOF) {
group = group()
if (group == null) {
break
}
groups.add(group)
}
return NeoLangProgramNode(groups)
}
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")
var attr = attribute()
if (attr != null) {
val attributes = mutableListOf(attr)
while (token.tokenType !== NeoLangTokenType.EOF
&& token.tokenType !== NeoLangTokenType.BRACKET_END
&& token.tokenType !== NeoLangTokenType.ARRAY_END
) {
attr = attribute()
if (attr == null) {
break
}
attributes.add(attr)
}
return NeoLangGroupNode(attributes.toTypedArray())
}
return null
}
private fun attribute(): NeoLangAttributeNode? {
val token = currentToken ?: throw InvalidTokenException("Unexpected token: null")
if (match(NeoLangTokenType.ID)) {
match(NeoLangTokenType.COLON, errorThrow = true)
val attrName = NeoLangStringNode(token)
val block = block(attrName) ?: NeoLangBlockNode.emptyNode()
return NeoLangAttributeNode(attrName, block)
}
return null
}
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(NeoLangArrayNode.Companion.ArrayElement(index++, block))
if (match(NeoLangTokenType.COMMA)) {
// More than one elements
while (token.tokenType !== NeoLangTokenType.EOF
&& token.tokenType !== NeoLangTokenType.ARRAY_END
) {
block = blockNonArrayElement(arrayName)
if (block == null) {
break
}
elements.add(NeoLangArrayNode.Companion.ArrayElement(index++, block))
// Meet the last element
if (!match(NeoLangTokenType.COMMA)) {
break
}
}
}
return NeoLangArrayNode(arrayName, elements.toTypedArray())
}
return null
}
/**
* @param attrName The block holder's name
*/
private fun block(attrName: NeoLangStringNode): NeoLangBlockNode? {
val block = blockNonArrayElement(attrName)
if (block != null) {
return block
}
val token = currentToken ?: throw InvalidTokenException("Unexpected token: null")
when (token.tokenType) {
NeoLangTokenType.ARRAY_START -> {
match(NeoLangTokenType.ARRAY_START, errorThrow = true)
val array = array(attrName)
match(NeoLangTokenType.ARRAY_END, errorThrow = true)
// Allow empty arrays
return if (array != null) NeoLangBlockNode(array) else NeoLangBlockNode.emptyNode()
}
else -> throw InvalidTokenException("Unexpected token `${token.tokenValue}' typed `${token.tokenType}' for block")
}
}
/**
* @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) {
NeoLangTokenType.NUMBER -> {
match(NeoLangTokenType.NUMBER, errorThrow = true)
return NeoLangBlockNode(NeoLangNumberNode(token))
}
NeoLangTokenType.ID -> {
match(NeoLangTokenType.ID, errorThrow = true)
return NeoLangBlockNode(NeoLangStringNode(token))
}
NeoLangTokenType.STRING -> {
match(NeoLangTokenType.STRING, errorThrow = true)
return NeoLangBlockNode(NeoLangStringNode(token))
}
NeoLangTokenType.BRACKET_START -> {
match(NeoLangTokenType.BRACKET_START, errorThrow = true)
val group = group()
match(NeoLangTokenType.BRACKET_END, errorThrow = true)
// Allow empty blocks
return if (group != null) NeoLangBlockNode(group) else NeoLangBlockNode.emptyNode()
}
else -> null
}
}
}
open class InvalidTokenException(message: String) : ParseException(message)
open class ParseException(message: String) : RuntimeException(message)

View File

@ -0,0 +1,114 @@
package io.neolang.frontend
import io.neolang.runtime.NeoLangValue
/**
* @author kiva
*/
open class NeoLangAst {
fun visit(): VisitorFactory {
return VisitorFactory(this)
}
}
open class NeoLangBaseNode : NeoLangAst()
/**
* @author kiva
*/
class NeoLangArrayNode(val arrayNameNode: NeoLangStringNode, val elements: Array<ArrayElement>) : NeoLangBaseNode() {
companion object {
class ArrayElement(val index: Int, val block: NeoLangBlockNode)
}
}
/**
* @author kiva
*/
open class NeoLangAstBasedNode(val ast: NeoLangBaseNode) : NeoLangBaseNode() {
override fun toString(): String {
return "${javaClass.simpleName} { ast: $ast }"
}
}
/**
* @author kiva
*/
class NeoLangAttributeNode(val stringNode: NeoLangStringNode, val blockNode: NeoLangBlockNode) : NeoLangBaseNode() {
override fun toString(): String {
return "NeoLangAttributeNode { stringNode: $stringNode, block: $blockNode }"
}
}
/**
* @author kiva
*/
class NeoLangBlockNode(blockElement: NeoLangBaseNode) : NeoLangAstBasedNode(blockElement) {
companion object {
fun emptyNode(): NeoLangBlockNode {
return NeoLangBlockNode(NeoLangDummyNode())
}
}
}
/**
* @author kiva
*/
class NeoLangDummyNode : NeoLangBaseNode()
/**
* @author kiva
*/
class NeoLangGroupNode(val attributes: Array<NeoLangAttributeNode>) : NeoLangBaseNode() {
override fun toString(): String {
return "NeoLangGroupNode { attrs: $attributes }"
}
companion object {
fun emptyNode(): NeoLangGroupNode {
return NeoLangGroupNode(arrayOf())
}
}
}
/**
* @author kiva
*/
class NeoLangNumberNode(token: NeoLangToken) : NeoLangTokenBasedNode(token)
/**
* @author kiva
*/
class NeoLangProgramNode(val groups: List<NeoLangGroupNode>) : NeoLangBaseNode() {
override fun toString(): String {
return "NeoLangProgramNode { groups: $groups }"
}
companion object {
fun emptyNode(): NeoLangProgramNode {
return NeoLangProgramNode(listOf())
}
}
}
/**
* @author kiva
*/
class NeoLangStringNode(token: NeoLangToken) : NeoLangTokenBasedNode(token)
/**
* @author kiva
*/
open class NeoLangTokenBasedNode(val token: NeoLangToken) : NeoLangBaseNode() {
override fun toString(): String {
return "${javaClass.simpleName} { token: $token }"
}
fun eval(): NeoLangValue {
return token.tokenValue.value
}
}

View File

@ -1,6 +1,41 @@
package io.neolang.ast package io.neolang.frontend
import io.neolang.runtime.type.NeoLangValue import io.neolang.runtime.NeoLangValue
/**
* @author kiva
*/
class NeoLangEOFToken : NeoLangToken(NeoLangTokenType.EOF, NeoLangTokenValue.EOF)
/**
* @author kiva
*/
open class NeoLangToken(val tokenType: NeoLangTokenType, val tokenValue: NeoLangTokenValue) {
var lineNumber = 0
override fun toString(): String {
return "Token { tokenType: $tokenType, tokenValue: $tokenValue };"
}
}
/**
* @author kiva
*/
enum class NeoLangTokenType {
NUMBER,
ID,
STRING,
BRACKET_START,
BRACKET_END,
ARRAY_START,
ARRAY_END,
COLON,
COMMA,
EOL,
EOF,
}
/** /**
* @author kiva * @author kiva

View File

@ -1,9 +1,9 @@
package io.neolang.visitor package io.neolang.frontend
import io.neolang.ast.visitor.IVisitorCallback import io.neolang.runtime.NeoLangArray
import io.neolang.runtime.context.NeoLangContext import io.neolang.runtime.NeoLangContext
import io.neolang.runtime.type.NeoLangArray import io.neolang.runtime.NeoLangValue
import io.neolang.runtime.type.NeoLangValue import java.util.*
class ConfigVisitor : IVisitorCallback { class ConfigVisitor : IVisitorCallback {
private var rootContext: NeoLangContext? = null private var rootContext: NeoLangContext? = null
@ -71,3 +71,40 @@ class ConfigVisitor : IVisitorCallback {
return currentContext!! return currentContext!!
} }
} }
/**
* @author kiva
*/
class DisplayProcessVisitor : IVisitorCallbackAdapter() {
private val contextStack = Stack<NeoLangContext>()
override fun onStart() {
println(">>> Start")
onEnterContext("global")
}
override fun onFinish() {
while (contextStack.isNotEmpty()) {
onExitContext()
}
println(">>> Finish")
}
override fun onEnterContext(contextName: String) {
val context = NeoLangContext(contextName)
contextStack.push(context)
println(">>> Entering Context `$contextName'")
}
override fun onExitContext() {
val context = contextStack.pop()
println(">>> Exiting & Dumping Context ${context.contextName}")
context.getAttributes().entries.forEach {
println(" > [${it.key}]: ${it.value.asString()}")
}
}
override fun getCurrentContext(): NeoLangContext {
return contextStack.peek()
}
}

View File

@ -1,40 +0,0 @@
package io.neolang.main
import io.neolang.parser.NeoLangParser
import io.neolang.visitor.DisplayProcessVisitor
import java.io.FileInputStream
/**
* @author kiva
*/
class Main {
companion object {
@JvmStatic
fun main(args: Array<String>) {
if (args.isEmpty()) {
println("Usage: NeoLang <program.nl>")
return
}
val parser = NeoLangParser()
args.forEach {
val programCode = readFully(it)
parser.setInputSource(programCode)
val ast = parser.parse()
println("Compile `$it'")
ast.visit()
.getVisitor(DisplayProcessVisitor::class.java)
?.start()
}
return
}
private fun readFully(file: String): String {
FileInputStream(file).use {
val bytes = ByteArray(it.available())
it.read(bytes)
return String(bytes)
}
}
}
}

View File

@ -1,6 +0,0 @@
package io.neolang.parser
/**
* @author kiva
*/
open class InvalidTokenException(message: String) : ParseException(message)

View File

@ -1,209 +0,0 @@
package io.neolang.parser
import io.neolang.ast.NeoLangToken
import io.neolang.ast.NeoLangTokenType
import io.neolang.ast.NeoLangTokenValue
import io.neolang.ast.base.NeoLangAst
import io.neolang.ast.node.*
/**
* @author kiva
*/
class NeoLangParser {
private val lexer = NeoLangLexer()
private var tokens = mutableListOf<NeoLangToken>()
private var currentPosition: Int = 0
private var currentToken: NeoLangToken? = null
fun setInputSource(programCode: String?) {
lexer.setInputSource(programCode)
}
fun parse(): NeoLangAst {
return updateParserStatus(lexer.lex()) ?: throw ParseException("AST is null")
}
private fun updateParserStatus(tokens: List<NeoLangToken>): NeoLangAst? {
if (tokens.isEmpty()) {
// Allow empty program
return NeoLangProgramNode.emptyNode()
}
this.tokens.clear()
this.tokens.addAll(tokens)
currentPosition = 0
currentToken = tokens[currentPosition]
return program()
}
private fun match(tokenType: NeoLangTokenType, errorThrow: Boolean = false): Boolean {
val currentToken = this.currentToken ?: throw InvalidTokenException("Unexpected token: null")
if (currentToken.tokenType === tokenType) {
currentPosition++
if (currentPosition >= tokens.size) {
this.currentToken = NeoLangToken(NeoLangTokenType.EOF, NeoLangTokenValue.EOF)
} else {
this.currentToken = tokens[currentPosition]
}
return true
} else if (errorThrow) {
throw InvalidTokenException(
"Unexpected token `${currentToken.tokenValue}' typed " +
"`${currentToken.tokenType}' near line ${currentToken.lineNumber}, " +
"expected $tokenType"
)
}
return false
}
private fun program(): NeoLangProgramNode {
val token = currentToken
var group = group()
if (group != null) {
val groups = mutableListOf(group)
while (token?.tokenType !== NeoLangTokenType.EOF) {
group = group()
if (group == null) {
break
}
groups.add(group)
}
return NeoLangProgramNode(groups)
}
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")
var attr = attribute()
if (attr != null) {
val attributes = mutableListOf(attr)
while (token.tokenType !== NeoLangTokenType.EOF
&& token.tokenType !== NeoLangTokenType.BRACKET_END
&& token.tokenType !== NeoLangTokenType.ARRAY_END
) {
attr = attribute()
if (attr == null) {
break
}
attributes.add(attr)
}
return NeoLangGroupNode(attributes.toTypedArray())
}
return null
}
private fun attribute(): NeoLangAttributeNode? {
val token = currentToken ?: throw InvalidTokenException("Unexpected token: null")
if (match(NeoLangTokenType.ID)) {
match(NeoLangTokenType.COLON, errorThrow = true)
val attrName = NeoLangStringNode(token)
val block = block(attrName) ?: NeoLangBlockNode.emptyNode()
return NeoLangAttributeNode(attrName, block)
}
return null
}
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(NeoLangArrayNode.Companion.ArrayElement(index++, block))
if (match(NeoLangTokenType.COMMA)) {
// More than one elements
while (token.tokenType !== NeoLangTokenType.EOF
&& token.tokenType !== NeoLangTokenType.ARRAY_END
) {
block = blockNonArrayElement(arrayName)
if (block == null) {
break
}
elements.add(NeoLangArrayNode.Companion.ArrayElement(index++, block))
// Meet the last element
if (!match(NeoLangTokenType.COMMA)) {
break
}
}
}
return NeoLangArrayNode(arrayName, elements.toTypedArray())
}
return null
}
/**
* @param attrName The block holder's name
*/
private fun block(attrName: NeoLangStringNode): NeoLangBlockNode? {
val block = blockNonArrayElement(attrName)
if (block != null) {
return block
}
val token = currentToken ?: throw InvalidTokenException("Unexpected token: null")
when (token.tokenType) {
NeoLangTokenType.ARRAY_START -> {
match(NeoLangTokenType.ARRAY_START, errorThrow = true)
val array = array(attrName)
match(NeoLangTokenType.ARRAY_END, errorThrow = true)
// Allow empty arrays
return if (array != null) NeoLangBlockNode(array) else NeoLangBlockNode.emptyNode()
}
else -> throw InvalidTokenException("Unexpected token `${token.tokenValue}' typed `${token.tokenType}' for block")
}
}
/**
* @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) {
NeoLangTokenType.NUMBER -> {
match(NeoLangTokenType.NUMBER, errorThrow = true)
return NeoLangBlockNode(NeoLangNumberNode(token))
}
NeoLangTokenType.ID -> {
match(NeoLangTokenType.ID, errorThrow = true)
return NeoLangBlockNode(NeoLangStringNode(token))
}
NeoLangTokenType.STRING -> {
match(NeoLangTokenType.STRING, errorThrow = true)
return NeoLangBlockNode(NeoLangStringNode(token))
}
NeoLangTokenType.BRACKET_START -> {
match(NeoLangTokenType.BRACKET_START, errorThrow = true)
val group = group()
match(NeoLangTokenType.BRACKET_END, errorThrow = true)
// Allow empty blocks
return if (group != null) NeoLangBlockNode(group) else NeoLangBlockNode.emptyNode()
}
else -> null
}
}
}

View File

@ -1,6 +0,0 @@
package io.neolang.parser
/**
* @author kiva
*/
open class ParseException(message: String) : RuntimeException(message)

View File

@ -1,6 +1,4 @@
package io.neolang.runtime.context package io.neolang.runtime
import io.neolang.runtime.type.NeoLangValue
/** /**
* @author kiva * @author kiva

View File

@ -1,18 +0,0 @@
package io.neolang.runtime.type
/**
* @author kiva
*/
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,30 +0,0 @@
package io.neolang.runtime.type
/**
* @author kiva
*/
class NeoLangValue(private val rawValue: Any) {
fun asString(): String {
return rawValue.toString()
}
fun asNumber(): Double {
if (rawValue is Array<*>) {
return 0.0
}
try {
return rawValue.toString().toDouble()
} catch (e: Throwable) {
return 0.0
}
}
fun isValid(): Boolean {
return this != UNDEFINED
}
companion object {
val UNDEFINED = NeoLangValue("<undefined>")
}
}

View File

@ -1,6 +1,4 @@
package io.neolang.runtime.type package io.neolang.runtime
import io.neolang.runtime.context.NeoLangContext
/** /**
* @author kiva * @author kiva
@ -60,3 +58,49 @@ class NeoLangArray private constructor(
return elements.iterator() return elements.iterator()
} }
} }
/**
* @author kiva
*/
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
}
}
/**
* @author kiva
*/
class NeoLangValue(private val rawValue: Any) {
fun asString(): String {
return rawValue.toString()
}
fun asNumber(): Double {
if (rawValue is Array<*>) {
return 0.0
}
try {
return rawValue.toString().toDouble()
} catch (e: Throwable) {
return 0.0
}
}
fun isValid(): Boolean {
return this != UNDEFINED
}
companion object {
val UNDEFINED = NeoLangValue("<undefined>")
}
}

View File

@ -1,42 +0,0 @@
package io.neolang.visitor
import io.neolang.ast.visitor.IVisitorCallbackAdapter
import io.neolang.runtime.context.NeoLangContext
import java.util.*
/**
* @author kiva
*/
class DisplayProcessVisitor : IVisitorCallbackAdapter() {
private val contextStack = Stack<NeoLangContext>()
override fun onStart() {
println(">>> Start")
onEnterContext("global")
}
override fun onFinish() {
while (contextStack.isNotEmpty()) {
onExitContext()
}
println(">>> Finish")
}
override fun onEnterContext(contextName: String) {
val context = NeoLangContext(contextName)
contextStack.push(context)
println(">>> Entering Context `$contextName'")
}
override fun onExitContext() {
val context = contextStack.pop()
println(">>> Exiting & Dumping Context ${context.contextName}")
context.getAttributes().entries.forEach {
println(" > [${it.key}]: ${it.value.asString()}")
}
}
override fun getCurrentContext(): NeoLangContext {
return contextStack.peek()
}
}

View File

@ -1,17 +0,0 @@
package io.neolang
import io.neolang.main.Main
import org.junit.Test
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see [Testing documentation](http://d.android.com/tools/testing)
*/
class NeoLangTest {
@Test
fun arrayTest() {
Main.main(arrayOf("NeoLang/example/extra-key.nl"))
}
}

View File

@ -1,41 +0,0 @@
package io.neoterm.component
import android.content.Context
import io.neoterm.component.codegen.CodeGenComponent
import io.neoterm.component.colorscheme.ColorSchemeComponent
import io.neoterm.component.completion.CompletionComponent
import io.neoterm.component.config.ConfigureComponent
import io.neoterm.component.extrakey.ExtraKeyComponent
import io.neoterm.component.font.FontComponent
import io.neoterm.component.pm.PackageComponent
import io.neoterm.component.profile.ProfileComponent
import io.neoterm.component.session.SessionComponent
import io.neoterm.component.session.ShellProfile
import io.neoterm.component.userscript.UserScriptComponent
import io.neoterm.utils.NLog
/**
* @author kiva
*/
object NeoInitializer {
fun init(context: Context) {
NLog.init(context)
initComponents()
}
fun initComponents() {
ComponentManager.registerComponent(ConfigureComponent::class.java)
ComponentManager.registerComponent(CodeGenComponent::class.java)
ComponentManager.registerComponent(ColorSchemeComponent::class.java)
ComponentManager.registerComponent(FontComponent::class.java)
ComponentManager.registerComponent(UserScriptComponent::class.java)
ComponentManager.registerComponent(ExtraKeyComponent::class.java)
ComponentManager.registerComponent(CompletionComponent::class.java)
ComponentManager.registerComponent(PackageComponent::class.java)
ComponentManager.registerComponent(SessionComponent::class.java)
ComponentManager.registerComponent(ProfileComponent::class.java)
val profileComp = ComponentManager.getComponent<ProfileComponent>()
profileComp.registerProfile(ShellProfile.PROFILE_META_NAME, ShellProfile::class.java)
}
}

View File

@ -1,7 +1,7 @@
package io.neoterm.component.colorscheme package io.neoterm.component.colorscheme
import android.content.Context import android.content.Context
import io.neolang.visitor.ConfigVisitor import io.neolang.frontend.ConfigVisitor
import io.neoterm.App import io.neoterm.App
import io.neoterm.R import io.neoterm.R
import io.neoterm.component.ComponentManager import io.neoterm.component.ComponentManager

View File

@ -1,6 +1,6 @@
package io.neoterm.component.colorscheme package io.neoterm.component.colorscheme
import io.neolang.visitor.ConfigVisitor import io.neolang.frontend.ConfigVisitor
import io.neoterm.backend.TerminalColorScheme import io.neoterm.backend.TerminalColorScheme
import io.neoterm.backend.TerminalColors import io.neoterm.backend.TerminalColors
import io.neoterm.component.ConfigFileBasedObject import io.neoterm.component.ConfigFileBasedObject

View File

@ -1,5 +1,18 @@
package io.neoterm.component package io.neoterm.component
import android.content.Context
import io.neoterm.component.codegen.CodeGenComponent
import io.neoterm.component.colorscheme.ColorSchemeComponent
import io.neoterm.component.completion.CompletionComponent
import io.neoterm.component.config.ConfigureComponent
import io.neoterm.component.extrakey.ExtraKeyComponent
import io.neoterm.component.font.FontComponent
import io.neoterm.component.pm.PackageComponent
import io.neoterm.component.profile.ProfileComponent
import io.neoterm.component.session.SessionComponent
import io.neoterm.component.session.ShellProfile
import io.neoterm.component.userscript.UserScriptComponent
import io.neoterm.utils.NLog
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
interface NeoComponent { interface NeoComponent {
@ -50,3 +63,28 @@ object ComponentManager {
class ComponentDuplicateException(serviceName: String) : RuntimeException("Service $serviceName duplicate") class ComponentDuplicateException(serviceName: String) : RuntimeException("Service $serviceName duplicate")
class ComponentNotFoundException(serviceName: String) : RuntimeException("Component `$serviceName' not found") class ComponentNotFoundException(serviceName: String) : RuntimeException("Component `$serviceName' not found")
/**
* @author kiva
*/
object NeoInitializer {
fun init(context: Context) {
NLog.init(context)
initComponents()
}
fun initComponents() {
ComponentManager.registerComponent(ConfigureComponent::class.java)
ComponentManager.registerComponent(CodeGenComponent::class.java)
ComponentManager.registerComponent(ColorSchemeComponent::class.java)
ComponentManager.registerComponent(FontComponent::class.java)
ComponentManager.registerComponent(UserScriptComponent::class.java)
ComponentManager.registerComponent(ExtraKeyComponent::class.java)
ComponentManager.registerComponent(CompletionComponent::class.java)
ComponentManager.registerComponent(PackageComponent::class.java)
ComponentManager.registerComponent(SessionComponent::class.java)
ComponentManager.registerComponent(ProfileComponent::class.java)
val profileComp = ComponentManager.getComponent<ProfileComponent>()
profileComp.registerProfile(ShellProfile.PROFILE_META_NAME, ShellProfile::class.java)
}
}

View File

@ -6,8 +6,8 @@ import android.preference.PreferenceManager
import android.system.ErrnoException import android.system.ErrnoException
import android.system.Os import android.system.Os
import android.util.TypedValue import android.util.TypedValue
import io.neolang.parser.NeoLangParser import io.neolang.frontend.ConfigVisitor
import io.neolang.visitor.ConfigVisitor import io.neolang.frontend.NeoLangParser
import io.neoterm.App import io.neoterm.App
import io.neoterm.R import io.neoterm.R
import io.neoterm.backend.TerminalSession import io.neoterm.backend.TerminalSession

View File

@ -1,7 +1,7 @@
package io.neoterm.component.config package io.neoterm.component.config
import io.neolang.runtime.type.NeoLangValue import io.neolang.frontend.ConfigVisitor
import io.neolang.visitor.ConfigVisitor import io.neolang.runtime.NeoLangValue
import io.neoterm.component.colorscheme.NeoColorScheme import io.neoterm.component.colorscheme.NeoColorScheme
import io.neoterm.component.extrakey.NeoExtraKey import io.neoterm.component.extrakey.NeoExtraKey
import io.neoterm.frontend.session.view.extrakey.TextButton import io.neoterm.frontend.session.view.extrakey.TextButton

View File

@ -1,6 +1,6 @@
package io.neoterm.component package io.neoterm.component
import io.neolang.visitor.ConfigVisitor import io.neolang.frontend.ConfigVisitor
import io.neoterm.component.config.ConfigureComponent import io.neoterm.component.config.ConfigureComponent
import io.neoterm.utils.NLog import io.neoterm.utils.NLog
import java.io.File import java.io.File

View File

@ -1,7 +1,7 @@
package io.neoterm.component.extrakey package io.neoterm.component.extrakey
import android.content.Context import android.content.Context
import io.neolang.visitor.ConfigVisitor import io.neolang.frontend.ConfigVisitor
import io.neoterm.App import io.neoterm.App
import io.neoterm.component.ConfigFileBasedComponent import io.neoterm.component.ConfigFileBasedComponent
import io.neoterm.component.config.NeoTermPath import io.neoterm.component.config.NeoTermPath

View File

@ -1,6 +1,6 @@
package io.neoterm.component.extrakey package io.neoterm.component.extrakey
import io.neolang.visitor.ConfigVisitor import io.neolang.frontend.ConfigVisitor
import io.neoterm.component.ConfigFileBasedObject import io.neoterm.component.ConfigFileBasedObject
import io.neoterm.frontend.session.view.extrakey.ExtraKeysView import io.neoterm.frontend.session.view.extrakey.ExtraKeysView
import io.neoterm.frontend.session.view.extrakey.IExtraButton import io.neoterm.frontend.session.view.extrakey.IExtraButton

View File

@ -1,6 +1,6 @@
package io.neoterm.component.profile package io.neoterm.component.profile
import io.neolang.visitor.ConfigVisitor import io.neolang.frontend.ConfigVisitor
import io.neoterm.component.ConfigFileBasedComponent import io.neoterm.component.ConfigFileBasedComponent
import io.neoterm.component.config.NeoTermPath import io.neoterm.component.config.NeoTermPath
import io.neoterm.utils.NLog import io.neoterm.utils.NLog

View File

@ -1,6 +1,6 @@
package io.neoterm.component.profile package io.neoterm.component.profile
import io.neolang.visitor.ConfigVisitor import io.neolang.frontend.ConfigVisitor
import io.neoterm.component.ComponentManager import io.neoterm.component.ComponentManager
import io.neoterm.component.ConfigFileBasedObject import io.neoterm.component.ConfigFileBasedObject
import io.neoterm.component.codegen.CodeGenObject import io.neoterm.component.codegen.CodeGenObject

View File

@ -1,7 +1,7 @@
package io.neoterm.component.session package io.neoterm.component.session
import android.content.Context import android.content.Context
import io.neolang.visitor.ConfigVisitor import io.neolang.frontend.ConfigVisitor
import io.neoterm.App import io.neoterm.App
import io.neoterm.R import io.neoterm.R
import io.neoterm.backend.TerminalSession import io.neoterm.backend.TerminalSession