A lightweight, multiplatform Kotlin script engine with native function integration
SMS is a simple yet powerful scripting language and engine built specifically for Kotlin Multiplatform projects. It provides precise error reporting with line and column information, making it ideal for embedded scripting scenarios where you need reliable error feedback.
- 🎯 Precise Error Reporting - Line and column information for all errors
- 🔌 Native Function Integration - Easy registration of Kotlin functions
- 🌐 Multiplatform - Works on JVM, JS, and Native targets
- 📦 Zero Dependencies - Pure Kotlin implementation
- 🚀 Performance - Recursive descent parser with efficient interpretation
- 🛡️ Type Safe - Proper value system with type checking
import at.crowdware.sms.ScriptEngine
// Create engine
val engine = ScriptEngine.withStandardLibrary()
// Execute script
val result = engine.executeAndGetKotlin("""
fun greet(name) {
return "Hello " + name + "!"
}
greet("World")
""")
println(result) // "Hello World!"val engine = ScriptEngine()
// Register custom function
engine.registerKotlinFunction("multiply") { args ->
val a = args.getOrNull(0) as? Int ?: 0
val b = args.getOrNull(1) as? Int ?: 0
a * b
}
// Use in script
val result = engine.executeAndGetKotlin("multiply(6, 7)")
println(result) // 42try {
engine.execute("var x = ")
} catch (e: ScriptError) {
println("Error at line ${e.line}, column ${e.column}: ${e.message}")
// Error at line 1, column 9: Expected expression
}var number = 42
var text = "Hello World"
var flag = true
var nothing = null
var list = [1, 2, 3]
fun add(a, b) {
return a + b
}
fun factorial(n) {
if (n <= 1) {
return 1
} else {
return n * factorial(n - 1)
}
}
// If statements
if (x > 0) {
println("Positive")
} else {
println("Zero or negative")
}
// While loops
var i = 0
while (i < 10) {
println(i)
i++
}
// For loops
for (var j = 0; j < 5; j++) {
println(j)
}
// For-in loops
var numbers = [1, 2, 3, 4, 5]
for (num in numbers) {
println(num)
}
var language = "es"
when (language) {
"de" -> "Deutsch"
"es" -> "Espaniol"
else -> "English"
}
var a = 10
var b = 5
when {
a > b -> "A > B"
b > a -> "B > A"
else -> "A = B"
}
var arr = [1, 2, 3]
arr.add(4)
arr.remove(2)
arr.removeAt(0)
println(arr.size) // 2
var item = arr[0]
arr[1] = 10
data class Person(name, age)
var person = Person("Alice", 30)
println(person.name) // Alice
var language = "en"
var label = " Initial "
get() = if (language == "de") "Bezeichner: $field" else "Label: $field"
set(value) = field = value.trim()
label // "Label: Initial"
label = " Hello "
label // "Label: Hello"
val engine = ScriptEngine()
engine.registerKotlinFunction("setProperty") { args ->
val key = args[0] as String
val value = args[1]
myConfig[key] = value
null
}
engine.execute("""
// Configuration script
setProperty("timeout", 5000)
setProperty("retries", 3)
setProperty("debug", true)
""")class ScriptEngine {
// Execute script and return SMS value
fun execute(source: String): Value
// Execute script and return Kotlin value
fun executeAndGetKotlin(source: String): Any?
// Register native function with SMS values
fun registerFunction(name: String, function: (List<Value>) -> Value)
// Register native function with Kotlin values
fun registerKotlinFunction(name: String, function: (List<Any?>) -> Any?)
// Validate script syntax
fun validateSyntax(source: String)
// Check if function exists
fun hasFunction(name: String): Boolean
// Get all function names
fun getFunctionNames(): Set<String>
}// Create engine with built-in functions
val engine = ScriptEngine.withStandardLibrary()Built-in functions:
println(message)- Print message to consolereadLine()- Read line from inputrandom()/random(max)/random(min, max)- Generate random numberssplit(string, delimiter)- Split string into arrayjoin(array, delimiter)- Join array elements into stringtoString(value)- Convert value to stringsize(array)- Get array size- Math functions:
abs(n),min(a, b),max(a, b) - Type checks:
isNumber(v),isString(v),isBoolean(v),isNull(v),isArray(v)
object SMS {
// Quick execute
fun execute(source: String): Any?
// Execute with custom functions
fun execute(source: String, functions: Map<String, (List<Any?>) -> Any?>): Any?
// Validate syntax
fun validate(source: String): Boolean
}SMS follows a clean three-phase architecture:
- Lexer (
Lexer.kt) - Tokenizes source code with position tracking - Parser (
Parser.kt) - Recursive descent parser creating AST nodes - Interpreter (
Interpreter.kt) - Tree-walking interpreter with scope management
- Position Tracking - Every token and AST node has line/column info
- Value System - Type-safe runtime values with Kotlin interop
- Native Functions - Easy registration of external functions
- Scope Management - Proper variable and function scoping
- Error Handling - Precise error reporting with context
Da die SMS Engine noch nicht bei Maven Central veröffentlicht ist, gibt es verschiedene Möglichkeiten sie zu nutzen:
- SMS Engine lokal publishen:
git clone https://github.com/CrowdWare/sms.git
cd sms
./gradlew publishToMavenLocal- In Ihrem Projekt verwenden:
// build.gradle.kts
repositories {
mavenLocal() // Wichtig: Local Maven Repository einbinden
mavenCentral()
}
dependencies {
implementation("at.crowdware:sms:1.11")
}- SMS als Subprojekt einbinden:
// settings.gradle.kts Ihres Projekts
includeBuild("../sms") // Pfad zum SMS Projekt- Dependency hinzufügen:
// build.gradle.kts
dependencies {
implementation("at.crowdware:sms")
}- SMS Engine bauen:
cd sms
./gradlew build- JAR Files kopieren:
# JAR Files finden sich in:
# build/libs/sms-jvm-1.0.0.jar (für JVM)
# build/libs/sms-js-1.0.0.klib (für JS)- Im Projekt einbinden:
// build.gradle.kts
dependencies {
implementation(files("libs/sms-jvm-1.0.0.jar"))
}Falls das Projekt auf GitHub veröffentlicht wird:
// build.gradle.kts
repositories {
maven("https://jitpack.io")
}
dependencies {
implementation("com.github.CrowdWare:sms:main-SNAPSHOT")
}Run tests:
./gradlew testThe test suite covers:
- Basic language features
- Error handling with position info
- Native function integration
- Standard library functions
- Edge cases and error conditions
Contributions are welcome! Areas for improvement:
- Additional built-in functions
- Performance optimizations
- Language features (classes, modules, etc.)
- Platform-specific integrations
GPL3 License - see LICENSE file for details.
SMS was created to solve the problem of unreliable error reporting in existing script engines. It prioritizes:
- Developer Experience - Clear error messages with exact positions
- Integration Simplicity - Easy native function registration
- Multiplatform Support - Works everywhere Kotlin does
- Maintainability - Clean, understandable architecture
Made with ❤️ by CrowdWare
Contact: art@crowdware.info