Implement some new stdlib functions and methods
This commit is contained in:
45
api/src/main/kotlin/io/smnp/ext/HybridModuleProvider.kt
Normal file
45
api/src/main/kotlin/io/smnp/ext/HybridModuleProvider.kt
Normal file
@@ -0,0 +1,45 @@
|
||||
package io.smnp.ext
|
||||
|
||||
import io.smnp.callable.function.Function
|
||||
import io.smnp.callable.method.Method
|
||||
import io.smnp.interpreter.LanguageModuleInterpreter
|
||||
import io.smnp.type.module.Module
|
||||
|
||||
abstract class HybridModuleProvider(path: String) : ModuleProvider(path) {
|
||||
open fun functions(): List<Function> = emptyList()
|
||||
open fun methods(): List<Method> = emptyList()
|
||||
open fun files() = listOf("main.mus")
|
||||
|
||||
override fun provideModule(interpreter: LanguageModuleInterpreter): Module {
|
||||
return provideNativeModule(interpreter).merge(provideLanguageModule(interpreter))
|
||||
}
|
||||
|
||||
private fun provideNativeModule(interpreter: LanguageModuleInterpreter): Module {
|
||||
return object : NativeModuleProvider(path) {
|
||||
override fun functions() = this@HybridModuleProvider.functions()
|
||||
override fun methods() = this@HybridModuleProvider.methods()
|
||||
}.provideModule(interpreter)
|
||||
}
|
||||
|
||||
// Disclaimer:
|
||||
// Unfortunately, LanguageModuleProvider cannot be reused here because
|
||||
// getResource() method returns null if is invoked from anonymous class's object instance.
|
||||
// Therefore it is need to have following code here.
|
||||
private fun provideLanguageModule(interpreter: LanguageModuleInterpreter): Module {
|
||||
val segments = path.split(".")
|
||||
val parentNodesChainPath = segments.dropLast(1).joinToString(".")
|
||||
val moduleName = segments.last()
|
||||
|
||||
val module = files()
|
||||
.asSequence()
|
||||
.map { it to javaClass.classLoader.getResource(it) }
|
||||
.map { it.first to (it.second?.readText() ?: throw RuntimeException("Module '$path' does not contain '${it.first}' file")) }
|
||||
.map { interpreter.run(it.second, "module $path::${it.first}") }
|
||||
.map { it.getRootModule() }
|
||||
.reduce { acc, module -> acc.merge(module) }
|
||||
|
||||
module.name = moduleName
|
||||
|
||||
return Module.create(parentNodesChainPath, children = listOf(module))
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,16 @@ function _flatten(list: list, output: list) {
|
||||
return output;
|
||||
}
|
||||
|
||||
function shuffle(list: list) {
|
||||
shuffled = list;
|
||||
list.size-1 as first ^ {
|
||||
second = random(0, list.size);
|
||||
shuffled = shuffled.swap(first, second);
|
||||
}
|
||||
|
||||
return shuffled;
|
||||
}
|
||||
|
||||
extend list {
|
||||
function flatten() {
|
||||
return flatten(this);
|
||||
@@ -52,4 +62,41 @@ extend list {
|
||||
function isNotEmpty() {
|
||||
return not this.isEmpty();
|
||||
}
|
||||
|
||||
function dropIndex(index: int) {
|
||||
output = [];
|
||||
i = 0;
|
||||
this as item ^ {
|
||||
if(index != i) {
|
||||
output = output + [this.get(i)];
|
||||
}
|
||||
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function put(index: int, value) {
|
||||
return (index as i ^ this.get(i)) + [value] + ((this.size-index) as i ^ this.get(i+index));
|
||||
}
|
||||
|
||||
function replace(index: int, value) {
|
||||
return this
|
||||
.dropIndex(index)
|
||||
.put(index, value);
|
||||
}
|
||||
|
||||
function swap(a: int, b: int) {
|
||||
A = this.get(a);
|
||||
B = this.get(b);
|
||||
|
||||
return this
|
||||
.replace(a, B)
|
||||
.replace(b, A);
|
||||
}
|
||||
|
||||
function shuffle() {
|
||||
return shuffle(this);
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,11 @@ import io.smnp.ext.lang.function.TypeOfFunction
|
||||
import io.smnp.ext.lang.method.CharAtMethod
|
||||
import io.smnp.ext.lang.method.ListAccessMethod
|
||||
import io.smnp.ext.lang.method.MapAccessMethod
|
||||
import io.smnp.ext.lang.method.StringifyMethod
|
||||
import org.pf4j.Extension
|
||||
|
||||
@Extension
|
||||
class LangModule : NativeModuleProvider("smnp.lang") {
|
||||
override fun functions() = listOf(IntConstructor(), NoteConstructor(), TypeOfFunction())
|
||||
override fun methods() = listOf(ListAccessMethod(), MapAccessMethod(), CharAtMethod())
|
||||
override fun methods() = listOf(ListAccessMethod(), MapAccessMethod(), CharAtMethod(), StringifyMethod())
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.smnp.ext.lang.method
|
||||
|
||||
import io.smnp.callable.method.Method
|
||||
import io.smnp.callable.method.MethodDefinitionTool
|
||||
import io.smnp.callable.signature.Signature.Companion.simple
|
||||
import io.smnp.type.matcher.Matcher.Companion.anyType
|
||||
import io.smnp.type.model.Value
|
||||
|
||||
class StringifyMethod : Method(anyType(), "toString") {
|
||||
override fun define(new: MethodDefinitionTool) {
|
||||
new method simple() body { _, obj, _ ->
|
||||
Value.string(obj.stringify())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
package io.smnp.ext
|
||||
|
||||
import io.smnp.ext.function.ModuloFunction
|
||||
import io.smnp.ext.function.RandomFunction
|
||||
import io.smnp.ext.function.RangeFunction
|
||||
import org.pf4j.Extension
|
||||
|
||||
@Extension
|
||||
class MathModule : NativeModuleProvider("smnp.math") {
|
||||
override fun functions() = listOf(ModuloFunction(), RangeFunction())
|
||||
class MathModule : HybridModuleProvider("smnp.math") {
|
||||
override fun functions() = listOf(ModuloFunction(), RangeFunction(), RandomFunction())
|
||||
override fun dependencies() = listOf("smnp.lang", "smnp.collection")
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.smnp.ext.function
|
||||
|
||||
import io.smnp.callable.function.Function
|
||||
import io.smnp.callable.function.FunctionDefinitionTool
|
||||
import io.smnp.callable.signature.Signature.Companion.simple
|
||||
import io.smnp.type.model.Value
|
||||
import kotlin.random.Random
|
||||
|
||||
class RandomFunction : Function("random") {
|
||||
override fun define(new: FunctionDefinitionTool) {
|
||||
new function simple() body { _, _ ->
|
||||
Value.float(Random.nextFloat())
|
||||
}
|
||||
}
|
||||
}
|
||||
82
modules/math/src/main/resources/main.mus
Normal file
82
modules/math/src/main/resources/main.mus
Normal file
@@ -0,0 +1,82 @@
|
||||
function random(min: int, max: int) {
|
||||
return Int(random() * (max-min) + min)
|
||||
}
|
||||
|
||||
function random(min: float, max: float) {
|
||||
return random() * (max-min) + min
|
||||
}
|
||||
|
||||
function min(numbers: list<int, float>) {
|
||||
if(numbers.isEmpty()) {
|
||||
throw "Empty lists are not supported";
|
||||
}
|
||||
|
||||
min = numbers.get(0);
|
||||
numbers as number ^ {
|
||||
if(number < min) {
|
||||
min = number;
|
||||
}
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
function max(numbers: list<int, float>) {
|
||||
if(numbers.isEmpty()) {
|
||||
throw "Empty lists are not supported";
|
||||
}
|
||||
|
||||
max = numbers.get(0);
|
||||
numbers as number ^ {
|
||||
if(number > max) {
|
||||
max = number;
|
||||
}
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
function sample(list: list) {
|
||||
return list.get(random(0, list.size));
|
||||
}
|
||||
|
||||
function pick(...items: map<string><>) {
|
||||
return pick(items);
|
||||
}
|
||||
|
||||
function pick(items: list<map<string><>>) {
|
||||
acc = 0;
|
||||
|
||||
items as (item, index) ^ {
|
||||
if(item.size != 2) {
|
||||
throw "Expected lists with two items: 'chance' and 'value'";
|
||||
}
|
||||
|
||||
if(not item.containsKey("chance")) {
|
||||
throw "Item " + (index+1) + " does not have 'chance' key";
|
||||
}
|
||||
|
||||
if(not item.containsKey("value")) {
|
||||
throw "Item " + (index+1) + " does not have 'value' key";
|
||||
}
|
||||
|
||||
if(typeOf(item.get("chance")) != "int") {
|
||||
throw "Expected 'chance' to be of int type";
|
||||
}
|
||||
|
||||
acc = acc + item.get("chance");
|
||||
}
|
||||
|
||||
if(acc != 100) {
|
||||
throw "The total sum of each item ('chance' key) should be equal to 100";
|
||||
}
|
||||
|
||||
acc = 0;
|
||||
random = random(0, 100);
|
||||
items as item ^ {
|
||||
acc = acc + item.get("chance");
|
||||
if(random < acc) {
|
||||
return item.get("value");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user