Feature: A new DSL for ColorScheme and ExtraKeysView and even more in future
This commit is contained in:
@ -1,10 +0,0 @@
|
|||||||
package io.neolang
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author kiva
|
|
||||||
*/
|
|
||||||
object Version {
|
|
||||||
const val MAJOR = 0
|
|
||||||
const val MINOR = 1
|
|
||||||
const val PATCH = 0
|
|
||||||
}
|
|
13
NeoLang/src/main/java/io/neolang/ast/NeoLangAttributeNode.kt
Normal file
13
NeoLang/src/main/java/io/neolang/ast/NeoLangAttributeNode.kt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package io.neolang.ast
|
||||||
|
|
||||||
|
import io.neolang.ast.base.NeoLangAstBaseNode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
class NeoLangAttributeNode(private val stringNode: NeoLangStringNode, private val blockNode: NeoLangBlockNode) : NeoLangAstBaseNode() {
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "NeoLangAttributeNode { stringNode: $stringNode, block: $blockNode }"
|
||||||
|
}
|
||||||
|
}
|
15
NeoLang/src/main/java/io/neolang/ast/NeoLangBlockNode.kt
Normal file
15
NeoLang/src/main/java/io/neolang/ast/NeoLangBlockNode.kt
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package io.neolang.ast
|
||||||
|
|
||||||
|
import io.neolang.ast.base.NeoLangAstBaseNode
|
||||||
|
import io.neolang.ast.typed.NeoLangAstTypedNode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
class NeoLangBlockNode(ast: NeoLangAstBaseNode) : NeoLangAstTypedNode(ast) {
|
||||||
|
companion object {
|
||||||
|
fun emptyNode() :NeoLangBlockNode {
|
||||||
|
return NeoLangBlockNode(NeoLangDummyNode())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
NeoLang/src/main/java/io/neolang/ast/NeoLangDummyNode.kt
Normal file
8
NeoLang/src/main/java/io/neolang/ast/NeoLangDummyNode.kt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package io.neolang.ast
|
||||||
|
|
||||||
|
import io.neolang.ast.base.NeoLangAstBaseNode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
class NeoLangDummyNode : NeoLangAstBaseNode()
|
6
NeoLang/src/main/java/io/neolang/ast/NeoLangEOFToken.kt
Normal file
6
NeoLang/src/main/java/io/neolang/ast/NeoLangEOFToken.kt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package io.neolang.ast
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
class NeoLangEOFToken : NeoLangToken(NeoLangTokenType.EOF, NeoLangTokenValue.EOF)
|
13
NeoLang/src/main/java/io/neolang/ast/NeoLangGroupNode.kt
Normal file
13
NeoLang/src/main/java/io/neolang/ast/NeoLangGroupNode.kt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package io.neolang.ast
|
||||||
|
|
||||||
|
import io.neolang.ast.base.NeoLangAstBaseNode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
class NeoLangGroupNode(private val attributes: List<NeoLangAttributeNode>) : NeoLangAstBaseNode() {
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "NeoLangGroupNode { attrs: $attributes }"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package io.neolang.ast
|
||||||
|
|
||||||
|
import io.neolang.ast.typed.NeoLangTokenTypedNode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
class NeoLangNumberNode(token: NeoLangToken) : NeoLangTokenTypedNode(token)
|
21
NeoLang/src/main/java/io/neolang/ast/NeoLangProgramNode.kt
Normal file
21
NeoLang/src/main/java/io/neolang/ast/NeoLangProgramNode.kt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package io.neolang.ast
|
||||||
|
|
||||||
|
import io.neolang.ast.base.NeoLangAstBaseNode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
|
||||||
|
class NeoLangProgramNode(private val groups: List<NeoLangGroupNode>) : NeoLangAstBaseNode() {
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "NeoLangProgramNode { groups: $groups }"
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun emptyNode() : NeoLangProgramNode {
|
||||||
|
return NeoLangProgramNode(listOf())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
|||||||
|
package io.neolang.ast
|
||||||
|
|
||||||
|
import io.neolang.ast.typed.NeoLangTokenTypedNode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
class NeoLangStringNode(token: NeoLangToken) : NeoLangTokenTypedNode(token)
|
13
NeoLang/src/main/java/io/neolang/ast/NeoLangToken.kt
Normal file
13
NeoLang/src/main/java/io/neolang/ast/NeoLangToken.kt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
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 };"
|
||||||
|
}
|
||||||
|
}
|
16
NeoLang/src/main/java/io/neolang/ast/NeoLangTokenType.kt
Normal file
16
NeoLang/src/main/java/io/neolang/ast/NeoLangTokenType.kt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package io.neolang.ast
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum class NeoLangTokenType {
|
||||||
|
NUMBER,
|
||||||
|
STRING,
|
||||||
|
BRACKET_START,
|
||||||
|
BRACKET_END,
|
||||||
|
COLON,
|
||||||
|
QUOTE,
|
||||||
|
EOL,
|
||||||
|
EOF,
|
||||||
|
}
|
24
NeoLang/src/main/java/io/neolang/ast/NeoLangTokenValue.kt
Normal file
24
NeoLang/src/main/java/io/neolang/ast/NeoLangTokenValue.kt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package io.neolang.ast
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
enum class NeoLangTokenValue(val value: String) {
|
||||||
|
COLON(":"),
|
||||||
|
BRACKET_START("{"),
|
||||||
|
BRACKET_END("}"),
|
||||||
|
QUOTE("\""),
|
||||||
|
EOF("");
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun wrap(tokenText: String): NeoLangTokenValue {
|
||||||
|
return when (tokenText) {
|
||||||
|
COLON.value -> COLON
|
||||||
|
BRACKET_START.value -> BRACKET_START
|
||||||
|
BRACKET_END.value -> BRACKET_END
|
||||||
|
QUOTE.value -> QUOTE
|
||||||
|
else -> EOF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
NeoLang/src/main/java/io/neolang/ast/base/NeoLangAst.kt
Normal file
12
NeoLang/src/main/java/io/neolang/ast/base/NeoLangAst.kt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package io.neolang.ast.base
|
||||||
|
|
||||||
|
import io.neolang.ast.visitor.NeoLangAstVisitor
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
open class NeoLangAst {
|
||||||
|
fun visit(): NeoLangAstVisitor {
|
||||||
|
return NeoLangAstVisitor(this)
|
||||||
|
}
|
||||||
|
}
|
3
NeoLang/src/main/java/io/neolang/ast/base/NeoLangAstBaseNode.kt
Executable file
3
NeoLang/src/main/java/io/neolang/ast/base/NeoLangAstBaseNode.kt
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
package io.neolang.ast.base
|
||||||
|
|
||||||
|
open class NeoLangAstBaseNode : NeoLangAst()
|
@ -0,0 +1,12 @@
|
|||||||
|
package io.neolang.ast.typed
|
||||||
|
|
||||||
|
import io.neolang.ast.base.NeoLangAstBaseNode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
open class NeoLangAstTypedNode(val ast: NeoLangAstBaseNode) : NeoLangAstBaseNode() {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "${javaClass.simpleName} { ast: $ast }"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package io.neolang.ast.typed
|
||||||
|
|
||||||
|
import io.neolang.ast.base.NeoLangAstBaseNode
|
||||||
|
import io.neolang.ast.NeoLangToken
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
open class NeoLangTokenTypedNode(val token: NeoLangToken) : NeoLangAstBaseNode() {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "${javaClass.simpleName} { token: $token }"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package io.neolang.ast.visitor
|
||||||
|
|
||||||
|
import io.neolang.ast.base.NeoLangAst
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
open class NeoLangAstVisitor(ast: NeoLangAst)
|
@ -0,0 +1,6 @@
|
|||||||
|
package io.neolang.parser
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
open class InvalidTokenException(message: String) : ParseException(message)
|
133
NeoLang/src/main/java/io/neolang/parser/NeoLangLexer.kt
Executable file
133
NeoLang/src/main/java/io/neolang/parser/NeoLangLexer.kt
Executable file
@ -0,0 +1,133 @@
|
|||||||
|
package io.neolang.parser
|
||||||
|
|
||||||
|
import io.neolang.ast.NeoLangEOFToken
|
||||||
|
import io.neolang.ast.NeoLangToken
|
||||||
|
import io.neolang.ast.NeoLangTokenType
|
||||||
|
import io.neolang.ast.NeoLangTokenValue
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* grammar: [
|
||||||
|
* prog: group (group)*
|
||||||
|
* group: attribute (attribute)*
|
||||||
|
* attribute: TEXT COLON block
|
||||||
|
* block: NUMBER | TEXT | (BRACKET_START group BRACKET_STOP)
|
||||||
|
* ]
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
class NeoLangLexer {
|
||||||
|
private var programCode: String? = null
|
||||||
|
private var currentPosition: Int = 0
|
||||||
|
private var currentChar: Char = ' '
|
||||||
|
private var lineNumber = 0
|
||||||
|
|
||||||
|
internal fun setInputSource(programCode: String?) {
|
||||||
|
this.programCode = programCode
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun lex(): List<NeoLangToken> {
|
||||||
|
val programCode = this.programCode ?: return listOf()
|
||||||
|
currentPosition = 0
|
||||||
|
lineNumber = 1
|
||||||
|
currentChar = programCode[currentPosition]
|
||||||
|
|
||||||
|
val tokens = ArrayList<NeoLangToken>()
|
||||||
|
while (currentPosition < programCode.length) {
|
||||||
|
val token = nextToken
|
||||||
|
if (token is NeoLangEOFToken) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
tokens.add(token)
|
||||||
|
}
|
||||||
|
return tokens
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun moveToNextChar(): Boolean {
|
||||||
|
val programCode = this.programCode ?: return false
|
||||||
|
currentPosition++
|
||||||
|
if (currentPosition >= programCode.length) {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
currentChar = programCode[currentPosition]
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val nextToken: NeoLangToken
|
||||||
|
get() {
|
||||||
|
val programCode = this.programCode ?: return NeoLangEOFToken()
|
||||||
|
|
||||||
|
while (currentChar == ' '
|
||||||
|
|| currentChar == '\t'
|
||||||
|
|| currentChar == '\n'
|
||||||
|
|| currentChar == '\r') {
|
||||||
|
if (currentChar == '\n') {
|
||||||
|
++lineNumber
|
||||||
|
}
|
||||||
|
// Skip white chars
|
||||||
|
moveToNextChar()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPosition >= programCode.length) {
|
||||||
|
return NeoLangEOFToken()
|
||||||
|
}
|
||||||
|
|
||||||
|
val currentToken = NeoLangTokenValue.wrap(currentChar.toString())
|
||||||
|
val token: NeoLangToken = when (currentToken) {
|
||||||
|
NeoLangTokenValue.COLON -> {
|
||||||
|
moveToNextChar()
|
||||||
|
NeoLangToken(NeoLangTokenType.COLON, currentToken)
|
||||||
|
}
|
||||||
|
NeoLangTokenValue.BRACKET_START -> {
|
||||||
|
moveToNextChar()
|
||||||
|
NeoLangToken(NeoLangTokenType.BRACKET_START, currentToken)
|
||||||
|
}
|
||||||
|
NeoLangTokenValue.BRACKET_END -> {
|
||||||
|
moveToNextChar()
|
||||||
|
NeoLangToken(NeoLangTokenType.BRACKET_END, currentToken)
|
||||||
|
}
|
||||||
|
NeoLangTokenValue.QUOTE -> {
|
||||||
|
moveToNextChar()
|
||||||
|
NeoLangToken(NeoLangTokenType.QUOTE, currentToken)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
if (Character.isDigit(currentChar)) {
|
||||||
|
NeoLangToken(NeoLangTokenType.NUMBER, NeoLangTokenValue.wrap(getNextTokenAsNumber()))
|
||||||
|
} else if (Character.isLetterOrDigit(currentChar)) {
|
||||||
|
NeoLangToken(NeoLangTokenType.STRING, NeoLangTokenValue.wrap(getNextTokenAsString()))
|
||||||
|
} else {
|
||||||
|
throw InvalidTokenException("Unexpected character: " + currentChar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
token.lineNumber = lineNumber
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getNextTokenAsNumber(): String {
|
||||||
|
return buildString {
|
||||||
|
while (Character.isDigit(currentChar)) {
|
||||||
|
append(currentChar)
|
||||||
|
if (!moveToNextChar()) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getNextTokenAsString(): String {
|
||||||
|
return buildString {
|
||||||
|
while (Character.isLetterOrDigit(currentChar)) {
|
||||||
|
append(currentChar)
|
||||||
|
if (!moveToNextChar()) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
134
NeoLang/src/main/java/io/neolang/parser/NeoLangParser.kt
Executable file
134
NeoLang/src/main/java/io/neolang/parser/NeoLangParser.kt
Executable file
@ -0,0 +1,134 @@
|
|||||||
|
package io.neolang.parser
|
||||||
|
|
||||||
|
import io.neolang.ast.*
|
||||||
|
import io.neolang.ast.base.NeoLangAst
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
class NeoLangParser {
|
||||||
|
var ast: NeoLangAst? = null
|
||||||
|
private set
|
||||||
|
|
||||||
|
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 {
|
||||||
|
updateParserStatus(lexer.lex())
|
||||||
|
return ast ?: throw ParseException("AST is null")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateParserStatus(tokens: List<NeoLangToken>) {
|
||||||
|
if (tokens.isEmpty()) {
|
||||||
|
throw ParseException("Input tokens must be non-empty")
|
||||||
|
}
|
||||||
|
this.tokens.clear()
|
||||||
|
this.tokens.addAll(tokens)
|
||||||
|
currentPosition = 0
|
||||||
|
currentToken = tokens[currentPosition]
|
||||||
|
ast = 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 type " +
|
||||||
|
"`${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()
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
attr = attribute()
|
||||||
|
if (attr == null) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
attributes.add(attr)
|
||||||
|
}
|
||||||
|
return NeoLangGroupNode(attributes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun attribute(): NeoLangAttributeNode? {
|
||||||
|
val token = currentToken ?: throw InvalidTokenException("Unexpected token: null")
|
||||||
|
if (match(NeoLangTokenType.STRING)) {
|
||||||
|
match(NeoLangTokenType.COLON, errorThrow = true)
|
||||||
|
val block = block() ?: NeoLangBlockNode.emptyNode()
|
||||||
|
return NeoLangAttributeNode(NeoLangStringNode(token), block)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun block(): NeoLangBlockNode? {
|
||||||
|
val token = currentToken ?: throw InvalidTokenException("Unexpected token: null")
|
||||||
|
when (token.tokenType) {
|
||||||
|
NeoLangTokenType.NUMBER -> {
|
||||||
|
match(NeoLangTokenType.NUMBER, errorThrow = true)
|
||||||
|
return NeoLangBlockNode(NeoLangNumberNode(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 -> throw InvalidTokenException("Unexpected token `$token' for block, " +
|
||||||
|
"expected `${NeoLangTokenType.NUMBER}', `${NeoLangTokenType.STRING}' or `${NeoLangTokenType.BRACKET_START}'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package io.neolang.parser
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kiva
|
||||||
|
*/
|
||||||
|
open class ParseException(message: String) : RuntimeException(message)
|
@ -1,10 +0,0 @@
|
|||||||
package io.neolang.token
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author kiva
|
|
||||||
*/
|
|
||||||
class Token {
|
|
||||||
lateinit var type: TokenType
|
|
||||||
lateinit var value: Any
|
|
||||||
lateinit var nextToken: Token
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
package io.neolang.token
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author kiva
|
|
||||||
*/
|
|
||||||
enum class TokenType {
|
|
||||||
TYPE_IDENTIFIER,
|
|
||||||
TYPE_STRING,
|
|
||||||
TYPE_INTEGER,
|
|
||||||
TYPE_BOOLEAN,
|
|
||||||
|
|
||||||
KEYWORD_DOLLAR, /* $ */
|
|
||||||
KEYWORD_USE /* @ */,
|
|
||||||
|
|
||||||
OPERATOR_BEGIN,
|
|
||||||
OPT_ADD, /* + */
|
|
||||||
OPT_SUB, /* - */
|
|
||||||
OPT_NAV, /* - (负号) */
|
|
||||||
OPT_MUL, /* * */
|
|
||||||
OPT_DIV, /* / */
|
|
||||||
OPT_MOD, /* % */
|
|
||||||
OPT_XOR, /* ^ */
|
|
||||||
OPT_AND, /* & */
|
|
||||||
OPT_OR, /* | */
|
|
||||||
LEFT_SHIFT, /* << */
|
|
||||||
RIGHT_SHIFT, /* >> */
|
|
||||||
OPERATOR_END,
|
|
||||||
|
|
||||||
LOGICAL_OPERATOR_BEGIN,
|
|
||||||
OPT_LAND, /* && */
|
|
||||||
OPT_LOR, /* || */
|
|
||||||
OPT_LE, /* <= */
|
|
||||||
OPT_LT, /* < */
|
|
||||||
OPT_GE, /* >= */
|
|
||||||
OPT_GT, /* > */
|
|
||||||
OPT_EQ, /* == */
|
|
||||||
OPT_NEQ, /* != */
|
|
||||||
OPT_NOT, /* ! */
|
|
||||||
LOGICAL_OPERATOR_END,
|
|
||||||
}
|
|
@ -55,5 +55,6 @@ dependencies {
|
|||||||
compile 'com.github.wrdlbrnft:sorted-list-adapter:0.2.0.19'
|
compile 'com.github.wrdlbrnft:sorted-list-adapter:0.2.0.19'
|
||||||
compile 'com.simplecityapps:recyclerview-fastscroll:1.0.16'
|
compile 'com.simplecityapps:recyclerview-fastscroll:1.0.16'
|
||||||
// compile 'com.ramotion.cardslider:card-slider:0.1.0'
|
// compile 'com.ramotion.cardslider:card-slider:0.1.0'
|
||||||
compile 'com.github.igalata:Bubble-Picker:v0.2.4'
|
// compile 'com.github.igalata:Bubble-Picker:v0.2.4'
|
||||||
|
implementation project(path: ':NeoLang')
|
||||||
}
|
}
|
||||||
|
@ -1,88 +1,30 @@
|
|||||||
package io.neoterm.ui.setup
|
package io.neoterm.ui.setup
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.support.v4.content.ContextCompat
|
|
||||||
import android.support.v7.app.AlertDialog
|
import android.support.v7.app.AlertDialog
|
||||||
import android.support.v7.app.AppCompatActivity
|
import android.support.v7.app.AppCompatActivity
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import com.igalata.bubblepicker.BubblePickerListener
|
|
||||||
import com.igalata.bubblepicker.adapter.BubblePickerAdapter
|
|
||||||
import com.igalata.bubblepicker.model.BubbleGradient
|
|
||||||
import com.igalata.bubblepicker.model.PickerItem
|
|
||||||
import com.igalata.bubblepicker.rendering.BubblePicker
|
|
||||||
import io.neoterm.R
|
import io.neoterm.R
|
||||||
import io.neoterm.backend.TerminalSession
|
|
||||||
import io.neoterm.customize.pm.NeoPackageManager
|
|
||||||
import io.neoterm.customize.pm.NeoPackageManagerUtils
|
|
||||||
import io.neoterm.customize.setup.BaseFileInstaller
|
import io.neoterm.customize.setup.BaseFileInstaller
|
||||||
import io.neoterm.preference.NeoPreference
|
|
||||||
import io.neoterm.preference.NeoTermPath
|
|
||||||
import io.neoterm.utils.PackageUtils
|
import io.neoterm.utils.PackageUtils
|
||||||
import io.neoterm.frontend.floating.TerminalDialog
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author kiva
|
* @author kiva
|
||||||
*/
|
*/
|
||||||
class SetupActivity : AppCompatActivity() {
|
class SetupActivity : AppCompatActivity() {
|
||||||
companion object {
|
|
||||||
private val DEFAULT_PACKAGES = arrayOf(
|
|
||||||
"zsh", "neoterm-core", "tmux", "nodejs",
|
|
||||||
"fish", "make", "gdb", "clang", "vim", "emacs", "nano",
|
|
||||||
"curl", "git", "python", "p7zip", "oh-my-zsh")
|
|
||||||
}
|
|
||||||
|
|
||||||
lateinit var picker: BubblePicker
|
|
||||||
lateinit var toast: Toast
|
lateinit var toast: Toast
|
||||||
var aptUpdated = false
|
var aptUpdated = false
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.ui_setup)
|
setContentView(R.layout.ui_setup)
|
||||||
picker = findViewById(R.id.bubble_picker) as BubblePicker
|
|
||||||
val nextButton = findViewById(R.id.setup_next) as Button
|
val nextButton = findViewById(R.id.setup_next) as Button
|
||||||
nextButton.setOnClickListener {
|
nextButton.setOnClickListener {
|
||||||
if (aptUpdated) {
|
|
||||||
val packageList = mutableListOf("apt", "install", "-y")
|
|
||||||
var withShell: String? = null
|
|
||||||
picker.selectedItems
|
|
||||||
.filterNotNull()
|
|
||||||
.forEach {
|
|
||||||
val name = it.title ?: ""
|
|
||||||
packageList.add(name)
|
|
||||||
if (name == "zsh" || name == "fish" || name == "bash"
|
|
||||||
|| name == "mosh" || name == "dash") {
|
|
||||||
withShell = name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (packageList.size == 0) {
|
|
||||||
return@setOnClickListener
|
|
||||||
}
|
|
||||||
|
|
||||||
TerminalDialog(this@SetupActivity)
|
|
||||||
.onFinish(object : TerminalDialog.SessionFinishedCallback {
|
|
||||||
override fun onSessionFinished(dialog: TerminalDialog, finishedSession: TerminalSession?) {
|
|
||||||
if (finishedSession?.exitStatus == 0) {
|
|
||||||
dialog.dismiss()
|
|
||||||
if (withShell != null) {
|
|
||||||
NeoPreference.setLoginShell(withShell!!)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dialog.setTitle(getString(R.string.error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.execute(NeoTermPath.APT_BIN_PATH, packageList.toTypedArray())
|
|
||||||
.show(getString(R.string.installer_message))
|
|
||||||
} else {
|
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
setupBubbles()
|
|
||||||
installBaseFiles()
|
installBaseFiles()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,84 +74,31 @@ class SetupActivity : AppCompatActivity() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ShowToast")
|
// private fun randomPackageList(): Array<String> {
|
||||||
private fun setupBubbles() {
|
// val list = mutableListOf<String>()
|
||||||
val titles =
|
// val pm = NeoPackageManager.get()
|
||||||
if (intent.getBooleanExtra("setup", false))
|
//
|
||||||
DEFAULT_PACKAGES
|
// val sourceFiles = NeoPackageManagerUtils.detectSourceFiles()
|
||||||
else
|
// pm.clearPackages()
|
||||||
randomPackageList()
|
// for (index in sourceFiles.indices) {
|
||||||
val colors = resources.obtainTypedArray(R.array.bubble_colors)
|
// pm.refreshPackageList(sourceFiles[index], false)
|
||||||
|
// }
|
||||||
toast = Toast.makeText(this, null, Toast.LENGTH_LONG)
|
//
|
||||||
|
// val limit = 20
|
||||||
picker.bubbleSize = 25
|
// val packageNames = pm.packages.keys
|
||||||
picker.adapter = object : BubblePickerAdapter {
|
// val packageCount = packageNames.size
|
||||||
override val totalCount = titles.size
|
// val random = Random()
|
||||||
override fun getItem(position: Int): PickerItem {
|
//
|
||||||
return PickerItem().apply {
|
// var i = 0
|
||||||
title = titles[position]
|
// while (i < limit) {
|
||||||
textColor = ContextCompat.getColor(this@SetupActivity, android.R.color.white)
|
// val randomIndex = Math.abs(random.nextInt()) % packageCount
|
||||||
gradient = BubbleGradient(colors.getColor((position * 2) % 8, 0),
|
// val packageName = packageNames.elementAt(randomIndex)
|
||||||
colors.getColor((position * 2) % 8 + 1, 0), BubbleGradient.VERTICAL)
|
// if (packageName.startsWith("lib") || packageName.endsWith("-dev")) {
|
||||||
}
|
// continue
|
||||||
}
|
// }
|
||||||
}
|
// list.add(packageName)
|
||||||
picker.listener = object : BubblePickerListener {
|
// ++i
|
||||||
override fun onBubbleSelected(item: PickerItem) {
|
// }
|
||||||
val packageName = item.title
|
// return list.toTypedArray()
|
||||||
val pm = NeoPackageManager.get()
|
// }
|
||||||
val packageInfo = pm.getPackageInfo(packageName)
|
|
||||||
if (packageInfo != null) {
|
|
||||||
val packageDesc = packageInfo.description
|
|
||||||
toast.cancel()
|
|
||||||
toast.setText(packageDesc)
|
|
||||||
toast.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBubbleDeselected(item: PickerItem) {
|
|
||||||
toast.cancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
colors.recycle()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun randomPackageList(): Array<String> {
|
|
||||||
val list = mutableListOf<String>()
|
|
||||||
val pm = NeoPackageManager.get()
|
|
||||||
|
|
||||||
val sourceFiles = NeoPackageManagerUtils.detectSourceFiles()
|
|
||||||
pm.clearPackages()
|
|
||||||
for (index in sourceFiles.indices) {
|
|
||||||
pm.refreshPackageList(sourceFiles[index], false)
|
|
||||||
}
|
|
||||||
|
|
||||||
val limit = DEFAULT_PACKAGES.size
|
|
||||||
val packageNames = pm.packages.keys
|
|
||||||
val packageCount = packageNames.size
|
|
||||||
val random = Random()
|
|
||||||
|
|
||||||
var i = 0
|
|
||||||
while (i < limit) {
|
|
||||||
val randomIndex = Math.abs(random.nextInt()) % packageCount
|
|
||||||
val packageName = packageNames.elementAt(randomIndex)
|
|
||||||
if (packageName.startsWith("lib") || packageName.endsWith("-dev")) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
list.add(packageName)
|
|
||||||
++i
|
|
||||||
}
|
|
||||||
return list.toTypedArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
picker.onResume()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
super.onPause()
|
|
||||||
picker.onPause()
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,10 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:backgroundColor="@android:color/white">
|
android:background="@android:color/white">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/titleTextView"
|
android:id="@+id/titleTextView"
|
||||||
@ -28,18 +27,6 @@
|
|||||||
android:textColor="@color/colorAccent"
|
android:textColor="@color/colorAccent"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/hintTextView"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:layout_margin="14dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:lineSpacingMultiplier="1"
|
|
||||||
android:text="@string/setup_info2"
|
|
||||||
android:textColor="#9b9b9b"
|
|
||||||
android:textSize="14sp" />
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/setup_next"
|
android:id="@+id/setup_next"
|
||||||
android:layout_gravity="end"
|
android:layout_gravity="end"
|
||||||
@ -52,9 +39,4 @@
|
|||||||
android:textColor="#9b9b9b"
|
android:textColor="#9b9b9b"
|
||||||
android:textStyle="bold" />
|
android:textStyle="bold" />
|
||||||
|
|
||||||
<com.igalata.bubblepicker.rendering.BubblePicker
|
|
||||||
android:id="@+id/bubble_picker"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
@ -1,21 +0,0 @@
|
|||||||
package io.neoterm
|
|
||||||
|
|
||||||
import io.neoterm.customize.pm.NeoPackageManager
|
|
||||||
import io.neoterm.customize.pm.NeoPackageManagerUtils
|
|
||||||
import org.junit.Test
|
|
||||||
import java.io.File
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Example local unit test, which will execute on the development machine (host).
|
|
||||||
*
|
|
||||||
* @see [Testing documentation](http://d.android.com/tools/testing)
|
|
||||||
*/
|
|
||||||
class ExampleUnitTest {
|
|
||||||
@Test
|
|
||||||
fun test_pkg_parser() {
|
|
||||||
val prefix = NeoPackageManagerUtils.detectSourceFilePrefix("https://baidu.com:81")
|
|
||||||
println(prefix)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
19
app/src/test/java/io/neoterm/NeoLangTest.kt
Normal file
19
app/src/test/java/io/neoterm/NeoLangTest.kt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package io.neoterm
|
||||||
|
|
||||||
|
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 testNeoLangParser() {
|
||||||
|
val parser = io.neolang.parser.NeoLangParser()
|
||||||
|
parser.setInputSource("app: { x: {} \n x: hello \n a: 1111 \n x: { x: 123 } }")
|
||||||
|
val ast = parser.parse()
|
||||||
|
println(ast)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Reference in New Issue
Block a user