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
import io.neolang.ast.base.NeoLangAst
import io.neolang.ast.node.*
import io.neolang.runtime.type.NeoLangValue
package io.neolang.frontend
import io.neolang.runtime.NeoLangContext
import io.neolang.runtime.NeoLangValue
/**
* 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
*/
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
@ -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
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)
* ]
*/
package io.neolang.frontend
/**
* @author kiva
@ -201,9 +187,7 @@ class NeoLangLexer {
var value = numberValue
var loop = moveToNextChar() // skip 'x' or 'X'
while (loop && (currentChar.isHexNumber())) {
value *= 16
+(currentChar.toInt().and(15))
+if (currentChar >= 'A') 9 else 0
value *= 16 + (currentChar.toInt().and(15)) + if (currentChar >= 'A') 9 else 0
loop = moveToNextChar()
}
return value
@ -270,3 +254,208 @@ class NeoLangLexer {
|| 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

View File

@ -1,9 +1,9 @@
package io.neolang.visitor
package io.neolang.frontend
import io.neolang.ast.visitor.IVisitorCallback
import io.neolang.runtime.context.NeoLangContext
import io.neolang.runtime.type.NeoLangArray
import io.neolang.runtime.type.NeoLangValue
import io.neolang.runtime.NeoLangArray
import io.neolang.runtime.NeoLangContext
import io.neolang.runtime.NeoLangValue
import java.util.*
class ConfigVisitor : IVisitorCallback {
private var rootContext: NeoLangContext? = null
@ -71,3 +71,40 @@ class ConfigVisitor : IVisitorCallback {
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
import io.neolang.runtime.type.NeoLangValue
package io.neolang.runtime
/**
* @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
import io.neolang.runtime.context.NeoLangContext
package io.neolang.runtime
/**
* @author kiva
@ -60,3 +58,49 @@ class NeoLangArray private constructor(
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
import android.content.Context
import io.neolang.visitor.ConfigVisitor
import io.neolang.frontend.ConfigVisitor
import io.neoterm.App
import io.neoterm.R
import io.neoterm.component.ComponentManager

View File

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

View File

@ -1,5 +1,18 @@
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
interface NeoComponent {
@ -50,3 +63,28 @@ object ComponentManager {
class ComponentDuplicateException(serviceName: String) : RuntimeException("Service $serviceName duplicate")
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.Os
import android.util.TypedValue
import io.neolang.parser.NeoLangParser
import io.neolang.visitor.ConfigVisitor
import io.neolang.frontend.ConfigVisitor
import io.neolang.frontend.NeoLangParser
import io.neoterm.App
import io.neoterm.R
import io.neoterm.backend.TerminalSession

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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