Feature: NeoLang

This commit is contained in:
zt515
2017-08-03 23:55:08 +08:00
parent df22d5cf53
commit d5b5755783
40 changed files with 264 additions and 126 deletions

View File

@ -30,3 +30,7 @@ compileTestKotlin {
jvmTarget = "1.8" jvmTarget = "1.8"
} }
} }
dependencies {
testCompile 'junit:junit:4.12'
}

View File

@ -1,15 +0,0 @@
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())
}
}
}

View File

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

View File

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

View File

@ -1,28 +1,30 @@
package io.neolang.ast package io.neolang.ast
import io.neolang.runtime.type.NeoLangValue
/** /**
* @author kiva * @author kiva
*/ */
class NeoLangTokenValue(val value: String) { class NeoLangTokenValue(val value: NeoLangValue) {
override fun toString(): String { override fun toString(): String {
return value return value.asString()
} }
companion object { companion object {
val COLON = NeoLangTokenValue(":") val COLON = NeoLangTokenValue(NeoLangValue(":"))
val BRACKET_START = NeoLangTokenValue("{") val BRACKET_START = NeoLangTokenValue(NeoLangValue("{"))
val BRACKET_END = NeoLangTokenValue("}") val BRACKET_END = NeoLangTokenValue(NeoLangValue("}"))
val QUOTE = NeoLangTokenValue("\"") val QUOTE = NeoLangTokenValue(NeoLangValue("\""))
val EOF = NeoLangTokenValue("<EOF>") val EOF = NeoLangTokenValue(NeoLangValue("<EOF>"))
fun wrap(tokenText: String): NeoLangTokenValue { fun wrap(tokenText: String): NeoLangTokenValue {
return when (tokenText) { return when (tokenText) {
COLON.value -> COLON COLON.value.asString() -> COLON
BRACKET_START.value -> BRACKET_START BRACKET_START.value.asString() -> BRACKET_START
BRACKET_END.value -> BRACKET_END BRACKET_END.value.asString() -> BRACKET_END
QUOTE.value -> QUOTE QUOTE.value.asString() -> QUOTE
else -> NeoLangTokenValue(tokenText) else -> NeoLangTokenValue(NeoLangValue(tokenText))
} }
} }
} }

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
package io.neolang.ast package io.neolang.ast.node
import io.neolang.ast.base.NeoLangAstBaseNode import io.neolang.ast.base.NeoLangAstBaseNode

View File

@ -1,11 +1,11 @@
package io.neolang.ast package io.neolang.ast.node
import io.neolang.ast.base.NeoLangAstBaseNode import io.neolang.ast.base.NeoLangAstBaseNode
/** /**
* @author kiva * @author kiva
*/ */
class NeoLangGroupNode(private val attributes: List<NeoLangAttributeNode>) : NeoLangAstBaseNode() { class NeoLangGroupNode(val attributes: List<NeoLangAttributeNode>) : NeoLangAstBaseNode() {
override fun toString(): String { override fun toString(): String {
return "NeoLangGroupNode { attrs: $attributes }" return "NeoLangGroupNode { attrs: $attributes }"

View File

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

View File

@ -1,4 +1,4 @@
package io.neolang.ast package io.neolang.ast.node
import io.neolang.ast.base.NeoLangAstBaseNode import io.neolang.ast.base.NeoLangAstBaseNode
@ -6,7 +6,7 @@ import io.neolang.ast.base.NeoLangAstBaseNode
* @author kiva * @author kiva
*/ */
class NeoLangProgramNode(private val groups: List<NeoLangGroupNode>) : NeoLangAstBaseNode() { class NeoLangProgramNode(val groups: List<NeoLangGroupNode>) : NeoLangAstBaseNode() {
override fun toString(): String { override fun toString(): String {
return "NeoLangProgramNode { groups: $groups }" return "NeoLangProgramNode { groups: $groups }"

View File

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

View File

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

View File

@ -7,6 +7,6 @@ import io.neolang.ast.base.NeoLangAst
*/ */
class AstVisitor(private val ast: NeoLangAst, private val visitorCallback: IVisitorCallback) { class AstVisitor(private val ast: NeoLangAst, private val visitorCallback: IVisitorCallback) {
fun start() { fun start() {
// TODO visitor AstVisitorImpl.visitStartAst(ast, visitorCallback)
} }
} }

View File

@ -0,0 +1,62 @@
package io.neolang.ast.visitor
import io.neolang.ast.base.NeoLangAst
import io.neolang.ast.node.*
/**
* grammar: [
* program: group (group)*
* group: attribute (attribute)*
* attribute: ID COLON block
* block: STRING | NUMBER | (BRACKET_START group BRACKET_END)
* ]
*/
/**
* @author kiva
*/
internal object AstVisitorImpl {
fun visitProgram(ast: NeoLangProgramNode, visitorCallback: IVisitorCallback) {
visitorCallback.onStart()
ast.groups.forEach { visitGroup(it, visitorCallback) }
visitorCallback.onFinish()
}
fun visitGroup(ast: NeoLangGroupNode, visitorCallback: IVisitorCallback) {
ast.attributes.forEach {
visitAttribute(it, visitorCallback)
}
}
fun visitAttribute(ast: NeoLangAttributeNode, visitorCallback: IVisitorCallback) {
visitBlock(ast.blockNode, ast.stringNode.eval().asString(), visitorCallback)
}
fun visitBlock(ast: NeoLangBlockNode, blockName: String, visitorCallback: IVisitorCallback) {
val visitingNode = ast.ast
when (visitingNode) {
is NeoLangGroupNode -> {
// is a sub block, e.g.
// block: { sub-block: {} }
visitorCallback.onEnterContext(blockName)
AstVisitorImpl.visitGroup(visitingNode, visitorCallback)
visitorCallback.onExitContext()
}
is NeoLangStringNode -> {
// block: { node: "hello" }
visitorCallback.getCurrentContext().defineAttribute(blockName, visitingNode.eval())
}
is NeoLangNumberNode -> {
// block: { node: 123.456 }
visitorCallback.getCurrentContext().defineAttribute(blockName, visitingNode.eval())
}
}
}
fun visitStartAst(ast: NeoLangAst, visitorCallback: IVisitorCallback) {
when (ast) {
is NeoLangProgramNode -> AstVisitorImpl.visitProgram(ast, visitorCallback)
is NeoLangGroupNode -> AstVisitorImpl.visitGroup(ast, visitorCallback)
}
}
}

View File

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

View File

@ -1,9 +0,0 @@
package io.neolang.main
import io.neolang.ast.visitor.IVisitorCallback
/**
* @author kiva
*/
class DisplayAstVisitor : IVisitorCallback {
}

View File

@ -0,0 +1,39 @@
package io.neolang.main
import io.neolang.ast.visitor.IVisitorCallback
import io.neolang.runtime.context.NeoLangContext
import java.util.*
/**
* @author kiva
*/
class DisplayProcessVisitor : IVisitorCallback {
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 Context ${context.contextName}")
}
override fun getCurrentContext(): NeoLangContext {
return contextStack.peek()
}
}

View File

@ -20,12 +20,10 @@ class Main {
val programCode = readFully(it) val programCode = readFully(it)
parser.setInputSource(programCode) parser.setInputSource(programCode)
val ast = parser.parse() val ast = parser.parse()
println("Compile `$it'")
val visitor = ast.visit().getVisitor(DisplayAstVisitor::class.java) ast.visit()
if (visitor != null) { .getVisitor(DisplayProcessVisitor::class.java)
println("Compile `$it' -> $ast") ?.start()
visitor.start()
}
} }
return return
} }

View File

@ -8,10 +8,10 @@ import java.util.*
/** /**
* grammar: [ * grammar: [
* prog: group (group)* * program: group (group)*
* group: attribute (attribute)* * group: attribute (attribute)*
* attribute: TEXT COLON block * attribute: ID COLON block
* block: NUMBER | TEXT | (BRACKET_START group BRACKET_END) * block: STRING | NUMBER | (BRACKET_START group BRACKET_END)
* ] * ]
*/ */
@ -122,7 +122,7 @@ class NeoLangLexer {
val builder = StringBuilder() val builder = StringBuilder()
var loop = true var loop = true
while (loop && currentChar != NeoLangTokenValue.QUOTE.value[0]) { while (loop && currentChar != NeoLangTokenValue.QUOTE.value.asString()[0]) {
// Skip escaped char // Skip escaped char
if (currentChar == '\\') { if (currentChar == '\\') {
builder.append('\\') builder.append('\\')

View File

@ -2,6 +2,7 @@ package io.neolang.parser
import io.neolang.ast.* import io.neolang.ast.*
import io.neolang.ast.base.NeoLangAst import io.neolang.ast.base.NeoLangAst
import io.neolang.ast.node.*
/** /**
* @author kiva * @author kiva

View File

@ -0,0 +1,8 @@
package io.neolang.runtime.context
/**
* @author kiva
*/
interface IContextMaker {
fun makeContext()
}

View File

@ -0,0 +1,18 @@
package io.neolang.runtime.context
import io.neolang.runtime.type.NeoLangValue
/**
* @author kiva
*/
class NeoLangContext(val contextName: String) {
private val attributes = mutableMapOf<String, NeoLangValue>()
fun defineAttribute(attributeName: String, attributeValue: NeoLangValue) {
attributes[attributeName] = attributeValue
}
fun getAttribute(attributeName: String) : NeoLangValue {
return attributes[attributeName] ?: NeoLangValue.UNDEFINED
}
}

View File

@ -0,0 +1,22 @@
package io.neolang.runtime.type
/**
* @author kiva
*/
class NeoLangValue(private val rawValue: Any) {
fun asString() : String {
return rawValue.toString()
}
fun asNumber() : Double {
try {
return asString().toDouble()
} catch (e: NumberFormatException) {
return 0.0
}
}
companion object {
val UNDEFINED = NeoLangValue("<undefined>")
}
}

View File

@ -1,4 +1,4 @@
package io.neoterm package io.neolang
import io.neolang.main.Main import io.neolang.main.Main
import org.junit.Test import org.junit.Test

View File

@ -1,25 +0,0 @@
package io.neoterm
import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumentation test, which will execute on an Android device.
*
* @see [Testing documentation](http://d.android.com/tools/testing)
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
@Throws(Exception::class)
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getTargetContext()
assertEquals("io.neoterm", appContext.packageName)
}
}

View File

@ -4,7 +4,7 @@ import android.app.AlertDialog
import android.content.Context import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import io.neoterm.backend.TerminalSession import io.neoterm.backend.TerminalSession
import io.neoterm.frontend.ShellParameter import io.neoterm.frontend.shell.ShellParameter
import io.neoterm.frontend.tinyclient.BasicSessionCallback import io.neoterm.frontend.tinyclient.BasicSessionCallback
import io.neoterm.frontend.tinyclient.BasicViewClient import io.neoterm.frontend.tinyclient.BasicViewClient
import io.neoterm.utils.TerminalUtils import io.neoterm.utils.TerminalUtils

View File

@ -0,0 +1,6 @@
package io.neoterm.frontend.service
/**
* @author kiva
*/
class ServiceDuplicateException(serviceName: String) : RuntimeException("Service $serviceName duplicate")

View File

@ -10,9 +10,12 @@ object ServiceManager {
val THROW_WHEN_SERVICE_NOT_FOUND = true val THROW_WHEN_SERVICE_NOT_FOUND = true
val SERVICE_CACHE = ConcurrentHashMap<Class<out NeoService>, NeoService>() val SERVICE_CACHE = ConcurrentHashMap<Class<out NeoService>, NeoService>()
fun registerService(serviceInterface: Class<out NeoService>) { fun registerService(serviceClass: Class<out NeoService>) {
val service = createServiceInstance(serviceInterface) if (SERVICE_CACHE.containsKey(serviceClass)) {
SERVICE_CACHE.put(serviceInterface, service) throw ServiceDuplicateException(serviceClass.simpleName)
}
val service = createServiceInstance(serviceClass)
SERVICE_CACHE.put(serviceClass, service)
service.onServiceInit() service.onServiceInit()
} }
@ -24,7 +27,6 @@ object ServiceManager {
} }
} }
@Suppress("UNCHECKED_CAST")
inline fun <reified T : NeoService> getService(): T { inline fun <reified T : NeoService> getService(): T {
Log.e("NeoTerm", SERVICE_CACHE.keys.toString()) Log.e("NeoTerm", SERVICE_CACHE.keys.toString())
val serviceInterface = T::class.java val serviceInterface = T::class.java

View File

@ -1,4 +1,4 @@
package io.neoterm.frontend package io.neoterm.frontend.shell
import io.neoterm.backend.TerminalSession import io.neoterm.backend.TerminalSession

View File

@ -1,4 +1,4 @@
package io.neoterm.frontend package io.neoterm.frontend.shell
import android.content.Context import android.content.Context
import io.neoterm.R import io.neoterm.R

View File

@ -15,7 +15,7 @@ import android.support.v4.content.WakefulBroadcastReceiver
import io.neoterm.R import io.neoterm.R
import io.neoterm.backend.EmulatorDebug import io.neoterm.backend.EmulatorDebug
import io.neoterm.backend.TerminalSession import io.neoterm.backend.TerminalSession
import io.neoterm.frontend.ShellParameter import io.neoterm.frontend.shell.ShellParameter
import io.neoterm.ui.term.NeoTermActivity import io.neoterm.ui.term.NeoTermActivity
import io.neoterm.utils.TerminalUtils import io.neoterm.utils.TerminalUtils
import java.util.* import java.util.*

View File

@ -13,7 +13,7 @@ import io.neoterm.backend.TerminalSession
import io.neoterm.customize.color.ColorSchemeManager import io.neoterm.customize.color.ColorSchemeManager
import io.neoterm.preference.NeoTermPath import io.neoterm.preference.NeoTermPath
import io.neoterm.customize.font.FontManager import io.neoterm.customize.font.FontManager
import io.neoterm.frontend.ShellParameter import io.neoterm.frontend.shell.ShellParameter
import io.neoterm.frontend.service.ServiceManager import io.neoterm.frontend.service.ServiceManager
import io.neoterm.utils.FileUtils import io.neoterm.utils.FileUtils
import io.neoterm.utils.MediaUtils import io.neoterm.utils.MediaUtils

View File

@ -22,14 +22,10 @@ import android.widget.Toast
import de.mrapp.android.tabswitcher.* import de.mrapp.android.tabswitcher.*
import io.neoterm.R import io.neoterm.R
import io.neoterm.backend.TerminalSession import io.neoterm.backend.TerminalSession
import io.neoterm.customize.color.ColorSchemeManager
import io.neoterm.customize.eks.ExtraKeysManager
import io.neoterm.customize.font.FontManager
import io.neoterm.customize.setup.BaseFileInstaller import io.neoterm.customize.setup.BaseFileInstaller
import io.neoterm.frontend.ShellParameter import io.neoterm.frontend.shell.ShellParameter
import io.neoterm.frontend.client.TermSessionCallback import io.neoterm.frontend.client.TermSessionCallback
import io.neoterm.frontend.client.TermViewClient import io.neoterm.frontend.client.TermViewClient
import io.neoterm.frontend.service.ServiceManager
import io.neoterm.preference.NeoPermission import io.neoterm.preference.NeoPermission
import io.neoterm.preference.NeoPreference import io.neoterm.preference.NeoPreference
import io.neoterm.services.NeoTermService import io.neoterm.services.NeoTermService
@ -309,7 +305,7 @@ class NeoTermActivity : AppCompatActivity(), ServiceConnection, SharedPreference
} }
private fun floatTabUp(tab: TermTab) { private fun floatTabUp(tab: TermTab) {
Toast.makeText(this, "In Progress", Toast.LENGTH_SHORT).show()
} }
private fun forceAddSystemSession() { private fun forceAddSystemSession() {

View File

@ -16,14 +16,13 @@ import android.widget.Toast
import io.neoterm.R import io.neoterm.R
import io.neoterm.customize.script.UserScript import io.neoterm.customize.script.UserScript
import io.neoterm.customize.script.UserScriptManager import io.neoterm.customize.script.UserScriptManager
import io.neoterm.frontend.ShellParameter import io.neoterm.frontend.shell.ShellParameter
import io.neoterm.frontend.client.TermSessionCallback import io.neoterm.frontend.client.TermSessionCallback
import io.neoterm.preference.NeoPreference import io.neoterm.preference.NeoPreference
import io.neoterm.services.NeoTermService import io.neoterm.services.NeoTermService
import io.neoterm.utils.TerminalUtils import io.neoterm.utils.TerminalUtils
import java.io.File import java.io.File
import android.content.Intent.ShortcutIconResource import android.content.Intent.ShortcutIconResource
import android.os.Parcelable
import io.neoterm.frontend.service.ServiceManager import io.neoterm.frontend.service.ServiceManager

View File

@ -23,6 +23,6 @@ object CrashHandler : Thread.UncaughtExceptionHandler {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.putExtra("exception", e) intent.putExtra("exception", e)
App.get().startActivity(intent) App.get().startActivity(intent)
Process.killProcess(Process.myPid()) defaultHandler.uncaughtException(t, e)
} }
} }

View File

@ -4,8 +4,8 @@ import android.content.Context
import io.neoterm.R import io.neoterm.R
import io.neoterm.backend.TerminalSession import io.neoterm.backend.TerminalSession
import io.neoterm.customize.font.FontManager import io.neoterm.customize.font.FontManager
import io.neoterm.frontend.ShellParameter import io.neoterm.frontend.shell.ShellParameter
import io.neoterm.frontend.ShellTermSession import io.neoterm.frontend.shell.ShellTermSession
import io.neoterm.frontend.service.ServiceManager import io.neoterm.frontend.service.ServiceManager
import io.neoterm.preference.NeoPreference import io.neoterm.preference.NeoPreference
import io.neoterm.view.eks.ExtraKeysView import io.neoterm.view.eks.ExtraKeysView

View File

@ -7,7 +7,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.0.0-alpha8' classpath 'com.android.tools.build:gradle:3.0.0-alpha9'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong

View File

@ -1,6 +1,6 @@
#Mon Jul 03 20:26:42 CST 2017 #Thu Aug 03 22:06:45 CST 2017
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-milestone-1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-rc-1-all.zip