Add support for providing modules written in SMNP language (LanguageModuleProvider extension class)
This commit is contained in:
20
api/src/main/kotlin/io/smnp/ext/LanguageModuleProvider.kt
Normal file
20
api/src/main/kotlin/io/smnp/ext/LanguageModuleProvider.kt
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package io.smnp.ext
|
||||||
|
|
||||||
|
import io.smnp.interpreter.Interpreter
|
||||||
|
import io.smnp.type.module.Module
|
||||||
|
|
||||||
|
abstract class LanguageModuleProvider(path: String) : ModuleProvider(path) {
|
||||||
|
open fun files() = listOf("main.mus")
|
||||||
|
|
||||||
|
override fun provideModule(interpreter: Interpreter): Module {
|
||||||
|
val module = Module.create(path)
|
||||||
|
interpreter.updateRootModule(module)
|
||||||
|
|
||||||
|
files()
|
||||||
|
.map { javaClass.classLoader.getResource(it) }
|
||||||
|
.map { it.readText() }
|
||||||
|
.forEach { interpreter.run(it) }
|
||||||
|
|
||||||
|
return module
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package io.smnp.ext
|
|
||||||
|
|
||||||
import io.smnp.callable.function.Function
|
|
||||||
import io.smnp.callable.method.Method
|
|
||||||
import io.smnp.type.module.Module
|
|
||||||
import org.pf4j.ExtensionPoint
|
|
||||||
|
|
||||||
abstract class ModuleDefinition(val path: String) : ExtensionPoint {
|
|
||||||
open fun functions(): List<Function> = emptyList()
|
|
||||||
open fun methods(): List<Method> = emptyList()
|
|
||||||
open fun dependencies(): List<String> = emptyList()
|
|
||||||
|
|
||||||
fun module(): Module = Module.create(path, functions(), methods())
|
|
||||||
}
|
|
||||||
10
api/src/main/kotlin/io/smnp/ext/ModuleProvider.kt
Normal file
10
api/src/main/kotlin/io/smnp/ext/ModuleProvider.kt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package io.smnp.ext
|
||||||
|
|
||||||
|
import io.smnp.interpreter.Interpreter
|
||||||
|
import io.smnp.type.module.Module
|
||||||
|
import org.pf4j.ExtensionPoint
|
||||||
|
|
||||||
|
abstract class ModuleProvider(val path: String) : ExtensionPoint {
|
||||||
|
open fun dependencies(): List<String> = emptyList()
|
||||||
|
abstract fun provideModule(interpreter: Interpreter): Module
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package io.smnp.ext
|
package io.smnp.ext
|
||||||
|
|
||||||
interface ModuleRegistry {
|
interface ModuleRegistry {
|
||||||
fun requestModulesForPath(path: String): ModuleDefinition?
|
fun requestModulesForPath(path: String): ModuleProvider?
|
||||||
fun registeredModules(): List<String>
|
fun registeredModules(): List<String>
|
||||||
}
|
}
|
||||||
13
api/src/main/kotlin/io/smnp/ext/NativeModuleProvider.kt
Normal file
13
api/src/main/kotlin/io/smnp/ext/NativeModuleProvider.kt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package io.smnp.ext
|
||||||
|
|
||||||
|
import io.smnp.callable.function.Function
|
||||||
|
import io.smnp.callable.method.Method
|
||||||
|
import io.smnp.interpreter.Interpreter
|
||||||
|
import io.smnp.type.module.Module
|
||||||
|
|
||||||
|
abstract class NativeModuleProvider(path: String) : ModuleProvider(path) {
|
||||||
|
open fun functions(): List<Function> = emptyList()
|
||||||
|
open fun methods(): List<Method> = emptyList()
|
||||||
|
|
||||||
|
final override fun provideModule(interpreter: Interpreter) = Module.create(path, functions(), methods())
|
||||||
|
}
|
||||||
8
api/src/main/kotlin/io/smnp/interpreter/Interpreter.kt
Normal file
8
api/src/main/kotlin/io/smnp/interpreter/Interpreter.kt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package io.smnp.interpreter
|
||||||
|
|
||||||
|
import io.smnp.type.module.Module
|
||||||
|
|
||||||
|
interface Interpreter {
|
||||||
|
fun run(code: String)
|
||||||
|
fun updateRootModule(newRootModule: Module): Unit = throw RuntimeException("Replacing root module is not supported in this Interpreter implementation")
|
||||||
|
}
|
||||||
@@ -4,13 +4,13 @@ import io.smnp.callable.function.Function
|
|||||||
import io.smnp.callable.method.Method
|
import io.smnp.callable.method.Method
|
||||||
import io.smnp.callable.signature.ActualSignatureFormatter.format
|
import io.smnp.callable.signature.ActualSignatureFormatter.format
|
||||||
import io.smnp.ext.DefaultModuleRegistry.requestModulesForPath
|
import io.smnp.ext.DefaultModuleRegistry.requestModulesForPath
|
||||||
import io.smnp.ext.ModuleDefinition
|
import io.smnp.ext.ModuleProvider
|
||||||
|
import io.smnp.interpreter.LanguageModuleInterpreter
|
||||||
import io.smnp.runtime.model.CallStack
|
import io.smnp.runtime.model.CallStack
|
||||||
import io.smnp.type.model.Value
|
import io.smnp.type.model.Value
|
||||||
import io.smnp.type.module.Module
|
import io.smnp.type.module.Module
|
||||||
|
|
||||||
class DefaultEnvironment : Environment {
|
class DefaultEnvironment(private val rootModule: Module = Module.create("<root>")) : Environment {
|
||||||
private val rootModule = Module("<root>")
|
|
||||||
private val loadedModules = mutableListOf<String>()
|
private val loadedModules = mutableListOf<String>()
|
||||||
private val callStack = CallStack()
|
private val callStack = CallStack()
|
||||||
|
|
||||||
@@ -25,13 +25,13 @@ class DefaultEnvironment : Environment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadModule(moduleDefinition: ModuleDefinition) {
|
private fun loadModule(moduleProvider: ModuleProvider) {
|
||||||
rootModule.addSubmodule(moduleDefinition.module())
|
rootModule.addSubmodule(moduleProvider.provideModule(LanguageModuleInterpreter()))
|
||||||
loadedModules.add(moduleDefinition.path)
|
loadedModules.add(moduleProvider.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadDependencies(moduleDefinition: ModuleDefinition) {
|
private fun loadDependencies(moduleProvider: ModuleProvider) {
|
||||||
moduleDefinition.dependencies().forEach { dependencyPath ->
|
moduleProvider.dependencies().forEach { dependencyPath ->
|
||||||
if (!loadedModules.contains(dependencyPath)) {
|
if (!loadedModules.contains(dependencyPath)) {
|
||||||
val dependency = requestModulesForPath(dependencyPath)
|
val dependency = requestModulesForPath(dependencyPath)
|
||||||
loadModule(dependency)
|
loadModule(dependency)
|
||||||
|
|||||||
@@ -37,6 +37,23 @@ abstract class Evaluator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun repeat(evaluator: Evaluator): Evaluator {
|
||||||
|
return object : Evaluator() {
|
||||||
|
override fun supportedNodes() = listOf(Node::class)
|
||||||
|
|
||||||
|
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
|
||||||
|
for (child in node.children) {
|
||||||
|
val output = evaluator.evaluate(child, environment)
|
||||||
|
if (output.result == EvaluationResult.FAILED) {
|
||||||
|
return EvaluatorOutput.fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EvaluatorOutput.ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun assert(evaluator: Evaluator, expected: String): Evaluator {
|
fun assert(evaluator: Evaluator, expected: String): Evaluator {
|
||||||
return object : Evaluator() {
|
return object : Evaluator() {
|
||||||
override fun supportedNodes() = listOf(Node::class)
|
override fun supportedNodes() = listOf(Node::class)
|
||||||
|
|||||||
@@ -4,27 +4,17 @@ import io.smnp.dsl.ast.model.node.Node
|
|||||||
import io.smnp.dsl.ast.model.node.RootNode
|
import io.smnp.dsl.ast.model.node.RootNode
|
||||||
import io.smnp.environment.Environment
|
import io.smnp.environment.Environment
|
||||||
import io.smnp.evaluation.model.entity.EvaluatorOutput
|
import io.smnp.evaluation.model.entity.EvaluatorOutput
|
||||||
import io.smnp.evaluation.model.enumeration.EvaluationResult
|
|
||||||
|
|
||||||
class RootEvaluator : Evaluator() {
|
class RootEvaluator : Evaluator() {
|
||||||
override fun supportedNodes() = listOf(RootNode::class)
|
override fun supportedNodes() = listOf(RootNode::class)
|
||||||
|
|
||||||
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
|
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
|
||||||
val evaluator = assert(oneOf(
|
return repeat(assert(oneOf(
|
||||||
ImportEvaluator(),
|
ImportEvaluator(),
|
||||||
ExpressionEvaluator(),
|
ExpressionEvaluator(),
|
||||||
FunctionDefinitionEvaluator(),
|
FunctionDefinitionEvaluator(),
|
||||||
ExtendEvaluator(),
|
ExtendEvaluator(),
|
||||||
DefaultEvaluator()
|
DefaultEvaluator()
|
||||||
), "correct statement")
|
), "correct statement")).evaluate(node, environment)
|
||||||
|
|
||||||
for(child in node.children) {
|
|
||||||
val output = evaluator.evaluate(child, environment)
|
|
||||||
if(output.result == EvaluationResult.FAILED) {
|
|
||||||
return EvaluatorOutput.fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return EvaluatorOutput.ok()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,18 +3,18 @@ package io.smnp.ext
|
|||||||
import org.pf4j.DefaultPluginManager
|
import org.pf4j.DefaultPluginManager
|
||||||
|
|
||||||
object DefaultModuleRegistry : ModuleRegistry {
|
object DefaultModuleRegistry : ModuleRegistry {
|
||||||
private val modules = mutableMapOf<String, ModuleDefinition>()
|
private val modules = mutableMapOf<String, ModuleProvider>()
|
||||||
init {
|
init {
|
||||||
val pluginManager = DefaultPluginManager()
|
val pluginManager = DefaultPluginManager()
|
||||||
pluginManager.loadPlugins()
|
pluginManager.loadPlugins()
|
||||||
pluginManager.startPlugins()
|
pluginManager.startPlugins()
|
||||||
|
|
||||||
pluginManager.getExtensions(ModuleDefinition::class.java).forEach {
|
pluginManager.getExtensions(ModuleProvider::class.java).forEach {
|
||||||
modules[it.path] = it
|
modules[it.path] = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun requestModulesForPath(path: String): ModuleDefinition {
|
override fun requestModulesForPath(path: String): ModuleProvider {
|
||||||
return modules[path] ?: throw RuntimeException("Module $path not found")
|
return modules[path] ?: throw RuntimeException("Module $path not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import io.smnp.evaluation.evaluator.RootEvaluator
|
|||||||
import io.smnp.evaluation.model.enumeration.EvaluationResult
|
import io.smnp.evaluation.model.enumeration.EvaluationResult
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class Interpreter {
|
class DefaultInterpreter : Interpreter {
|
||||||
private val tokenizer = DefaultTokenizer()
|
private val tokenizer = DefaultTokenizer()
|
||||||
private val parser = RootParser()
|
private val parser = RootParser()
|
||||||
private val evaluator = RootEvaluator()
|
private val evaluator = RootEvaluator()
|
||||||
@@ -46,4 +46,6 @@ class Interpreter {
|
|||||||
val lines = file.readLines()
|
val lines = file.readLines()
|
||||||
run(lines, printTokens, printAst, dryRun)
|
run(lines, printTokens, printAst, dryRun)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun run(code: String) = run(code, printTokens = false, printAst = false, dryRun = false)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package io.smnp.interpreter
|
||||||
|
|
||||||
|
import io.smnp.dsl.ast.parser.RootParser
|
||||||
|
import io.smnp.dsl.token.tokenizer.DefaultTokenizer
|
||||||
|
import io.smnp.environment.DefaultEnvironment
|
||||||
|
import io.smnp.environment.Environment
|
||||||
|
import io.smnp.evaluation.evaluator.Evaluator
|
||||||
|
import io.smnp.evaluation.evaluator.ExtendEvaluator
|
||||||
|
import io.smnp.evaluation.evaluator.FunctionDefinitionEvaluator
|
||||||
|
import io.smnp.evaluation.model.enumeration.EvaluationResult
|
||||||
|
import io.smnp.type.module.Module
|
||||||
|
|
||||||
|
class LanguageModuleInterpreter : Interpreter {
|
||||||
|
private var rootModule = Module.create("<root>")
|
||||||
|
private val tokenizer = DefaultTokenizer()
|
||||||
|
private val parser = RootParser()
|
||||||
|
private val evaluator = Evaluator.repeat(
|
||||||
|
Evaluator.assert(Evaluator.oneOf(
|
||||||
|
FunctionDefinitionEvaluator(),
|
||||||
|
ExtendEvaluator()
|
||||||
|
), "function definition or extend statement")
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun updateRootModule(newRootModule: Module) {
|
||||||
|
rootModule = newRootModule
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun run(code: String) {
|
||||||
|
val lines = code.split("\n")
|
||||||
|
val tokens = tokenizer.tokenize(lines)
|
||||||
|
val ast = parser.parse(tokens)
|
||||||
|
|
||||||
|
val environment = createEnvironment()
|
||||||
|
val result = evaluator.evaluate(ast.node, environment)
|
||||||
|
|
||||||
|
if (result.result == EvaluationResult.FAILED) {
|
||||||
|
throw RuntimeException("Evaluation failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createEnvironment(): Environment {
|
||||||
|
val environment = DefaultEnvironment(rootModule)
|
||||||
|
environment.loadModule("smnp.lang")
|
||||||
|
|
||||||
|
return environment
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package io.smnp.ext.io
|
package io.smnp.ext.io
|
||||||
|
|
||||||
import io.smnp.ext.ModuleDefinition
|
import io.smnp.ext.NativeModuleProvider
|
||||||
import io.smnp.ext.io.function.PrintlnFunction
|
import io.smnp.ext.io.function.PrintlnFunction
|
||||||
import org.pf4j.Extension
|
import org.pf4j.Extension
|
||||||
|
|
||||||
@Extension
|
@Extension
|
||||||
class IoModule : ModuleDefinition("smnp.io") {
|
class IoModule : NativeModuleProvider("smnp.io") {
|
||||||
override fun functions() = listOf(PrintlnFunction())
|
override fun functions() = listOf(PrintlnFunction())
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
package io.smnp.ext.lang
|
package io.smnp.ext.lang
|
||||||
|
|
||||||
import io.smnp.ext.ModuleDefinition
|
import io.smnp.ext.NativeModuleProvider
|
||||||
import io.smnp.ext.lang.function.DebugFunction
|
import io.smnp.ext.lang.function.DebugFunction
|
||||||
import io.smnp.ext.lang.method.ListAccessMethod
|
import io.smnp.ext.lang.method.ListAccessMethod
|
||||||
import io.smnp.ext.lang.method.MapAccessMethod
|
import io.smnp.ext.lang.method.MapAccessMethod
|
||||||
import org.pf4j.Extension
|
import org.pf4j.Extension
|
||||||
|
|
||||||
@Extension
|
@Extension
|
||||||
class LangModule : ModuleDefinition("smnp.lang") {
|
class LangModule : NativeModuleProvider("smnp.lang") {
|
||||||
override fun functions() = listOf(DebugFunction())
|
override fun functions() = listOf(DebugFunction())
|
||||||
override fun methods() = listOf(ListAccessMethod(), MapAccessMethod())
|
override fun methods() = listOf(ListAccessMethod(), MapAccessMethod())
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user