MISC: even more flatten!
This commit is contained in:
parent
56167cce5d
commit
236072395c
@ -1,6 +0,0 @@
|
|||||||
package io.neolang.ast
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author kiva
|
|
||||||
*/
|
|
||||||
class NeoLangEOFToken : NeoLangToken(NeoLangTokenType.EOF, NeoLangTokenValue.EOF)
|
|
@ -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 };"
|
|
||||||
}
|
|
||||||
}
|
|
@ -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,
|
|
||||||
}
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
package io.neolang.ast.base
|
|
||||||
|
|
||||||
open class NeoLangBaseNode : NeoLangAst()
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 }"
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 }"
|
|
||||||
}
|
|
||||||
}
|
|
@ -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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package io.neolang.ast.node
|
|
||||||
|
|
||||||
import io.neolang.ast.base.NeoLangBaseNode
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author kiva
|
|
||||||
*/
|
|
||||||
class NeoLangDummyNode : NeoLangBaseNode()
|
|
@ -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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package io.neolang.ast.node
|
|
||||||
|
|
||||||
import io.neolang.ast.NeoLangToken
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author kiva
|
|
||||||
*/
|
|
||||||
class NeoLangNumberNode(token: NeoLangToken) : NeoLangTokenBasedNode(token)
|
|
@ -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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
|||||||
package io.neolang.ast.node
|
|
||||||
|
|
||||||
import io.neolang.ast.NeoLangToken
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author kiva
|
|
||||||
*/
|
|
||||||
class NeoLangStringNode(token: NeoLangToken) : NeoLangTokenBasedNode(token)
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
|
||||||
}
|
|
@ -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!")
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
225
NeoLang/src/main/java/io/neolang/parser/NeoLangLexer.kt → NeoLang/src/main/java/io/neolang/frontend/frontend.kt
Executable file → Normal file
225
NeoLang/src/main/java/io/neolang/parser/NeoLangLexer.kt → NeoLang/src/main/java/io/neolang/frontend/frontend.kt
Executable file → Normal 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)
|
114
NeoLang/src/main/java/io/neolang/frontend/nodes.kt
Normal file
114
NeoLang/src/main/java/io/neolang/frontend/nodes.kt
Normal 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
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
package io.neolang.parser
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author kiva
|
|
||||||
*/
|
|
||||||
open class InvalidTokenException(message: String) : ParseException(message)
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
package io.neolang.parser
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author kiva
|
|
||||||
*/
|
|
||||||
open class ParseException(message: String) : RuntimeException(message)
|
|
@ -1,6 +1,4 @@
|
|||||||
package io.neolang.runtime.context
|
package io.neolang.runtime
|
||||||
|
|
||||||
import io.neolang.runtime.type.NeoLangValue
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kiva
|
* @author kiva
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
@ -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>")
|
|
||||||
}
|
|
||||||
}
|
|
@ -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>")
|
||||||
|
}
|
||||||
|
}
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
@ -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"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user