Add support for passing custom parameters to script

This commit is contained in:
2020-03-15 00:12:43 +01:00
parent 4ce35ce34c
commit 88b841bb98
5 changed files with 52 additions and 22 deletions

View File

@@ -4,7 +4,7 @@ import io.smnp.data.entity.Note
import io.smnp.type.model.Value import io.smnp.type.model.Value
import kotlin.reflect.KClass import kotlin.reflect.KClass
enum class DataType(val kotlinType: KClass<out Any>, val stringifier: (Any) -> String) { enum class DataType(private val kotlinType: KClass<out Any>, val stringifier: (Any) -> String) {
INT(Int::class, { it.toString() }), INT(Int::class, { it.toString() }),
FLOAT(Float::class, { it.toString() }), FLOAT(Float::class, { it.toString() }),
STRING(String::class, { it.toString() }), STRING(String::class, { it.toString() }),

View File

@@ -41,6 +41,20 @@ data class Value(val type: DataType, val value: Any, val properties: Map<String,
return Value(DataType.INT, value) return Value(DataType.INT, value)
} }
fun wrap(obj: Any): Value {
return when(obj) {
is Unit -> void()
is Int -> int(obj)
is Float -> float(obj)
is Boolean -> bool(obj)
is String -> string(obj)
is Note -> note(obj)
is List<*> -> list((obj as List<Any>).map { wrap(it) })
is Map<*, *> -> map((obj as Map<Any, Any>).map { (k, v) -> wrap(k) to wrap(v) }.toMap())
else -> throw ShouldNeverReachThisLineException()
}
}
fun float(value: Float): Value { fun float(value: Float): Value {
return Value( return Value(
DataType.FLOAT, DataType.FLOAT,

View File

@@ -7,22 +7,26 @@ import io.smnp.cli.model.enumeration.ModulesPrintMode
import io.smnp.environment.DefaultEnvironment import io.smnp.environment.DefaultEnvironment
import io.smnp.ext.DefaultModuleRegistry import io.smnp.ext.DefaultModuleRegistry
import io.smnp.interpreter.DefaultInterpreter import io.smnp.interpreter.DefaultInterpreter
import io.smnp.type.model.Value
fun main(args: Array<String>): Unit = mainBody { fun main(args: Array<String>): Unit = mainBody {
ArgParser(args).parseInto(::Arguments).run { ArgParser(args).parseInto(::Arguments).run {
val interpreter = DefaultInterpreter() val interpreter = DefaultInterpreter()
val environment = DefaultEnvironment()
environment.setVariable("__param__", Value.wrap(parameters.toMap()))
when { when {
file != null -> interpreter.run(file!!, printTokens, printAst, dryRun) file != null -> interpreter.run(file!!, environment, printTokens, printAst, dryRun)
code != null -> interpreter.run(code!!, printTokens, printAst, dryRun) code != null -> interpreter.run(code!!, environment, printTokens, printAst, dryRun)
else -> null else -> null
}?.let { it as DefaultEnvironment }?.let { environment -> }?.let { it as DefaultEnvironment }?.let { disposedEnvironment ->
if(loadedModules != null) { if(loadedModules != null) {
println("Loaded modules:") println("Loaded modules:")
when (loadedModules) { when (loadedModules) {
ModulesPrintMode.LIST -> environment.modules.forEach { println(it) } ModulesPrintMode.LIST -> disposedEnvironment.modules.forEach { println(it) }
ModulesPrintMode.TREE -> environment.printModules(false) ModulesPrintMode.TREE -> disposedEnvironment.printModules(false)
ModulesPrintMode.CONTENT -> environment.printModules(true) ModulesPrintMode.CONTENT -> disposedEnvironment.printModules(true)
} }
} }
} }

View File

@@ -17,6 +17,23 @@ class Arguments(parser: ArgParser) {
"prints loaded modules as list of canonical names of each one. The 'tree' option organises modules into the tree model " + "prints loaded modules as list of canonical names of each one. The 'tree' option organises modules into the tree model " +
"and then prints them. The 'content' option is the same as tree, however, prints also contained functions and methods." "and then prints them. The 'content' option is the same as tree, however, prints also contained functions and methods."
) { ModulesPrintMode.valueOf(this.toUpperCase()) }.default<ModulesPrintMode?>(null) ) { ModulesPrintMode.valueOf(this.toUpperCase()) }.default<ModulesPrintMode?>(null)
val parameters by parser.adding(
"-P", "--parameter", help = "define parameter to be consumed in script. Default syntax for parameter " +
"is 'key=value' (whitespaces around '=' are not allowed). In this case value will be of string type. " +
"However, it is also possible to pass parameter without any value. In this case, value will be of bool type. " +
"The parameters are available through global-accessible variable of map type and of '__param__' name."
) {
this.split("=").let {
when (it.size) {
1 -> it[0] to true
else -> it[0] to it.subList(1, it.size).joinToString("=")
}
}
}
val code by parser.storing("-c", "--code", help = "inline code to be executed").default<String?>(null) val code by parser.storing("-c", "--code", help = "inline code to be executed").default<String?>(null)
val file by parser.positional("SOURCE", help = "file with SMNP language code to be executed") { File(this) }.default<File?>(null) val file by parser.positional(
"SOURCE",
help = "file with SMNP language code to be executed"
) { File(this) }.default<File?>(null)
} }

View File

@@ -18,17 +18,18 @@ class DefaultInterpreter : Interpreter {
fun run( fun run(
code: String, code: String,
environment: Environment = DefaultEnvironment(),
printTokens: Boolean = false, printTokens: Boolean = false,
printAst: Boolean = false, printAst: Boolean = false,
dryRun: Boolean = false dryRun: Boolean = false
): Environment { ): Environment {
val lines = code.split("\n") val lines = code.split("\n")
return run(lines, printTokens, printAst, dryRun) return run(lines, environment, printTokens, printAst, dryRun)
} }
private fun run(lines: List<String>, printTokens: Boolean, printAst: Boolean, dryRun: Boolean): Environment { private fun run(lines: List<String>, environment: Environment, printTokens: Boolean, printAst: Boolean, dryRun: Boolean): Environment {
try { try {
return tryToRun(lines, printTokens, printAst, dryRun) return tryToRun(lines, environment, printTokens, printAst, dryRun)
} catch (e: SmnpException) { } catch (e: SmnpException) {
printError(e) printError(e)
exitProcess(1) exitProcess(1)
@@ -40,8 +41,9 @@ class DefaultInterpreter : Interpreter {
err.println(e.message) err.println(e.message)
} }
private fun tryToRun(lines: List<String>, printTokens: Boolean, printAst: Boolean, dryRun: Boolean): Environment { private fun tryToRun(lines: List<String>, environment: Environment, printTokens: Boolean, printAst: Boolean, dryRun: Boolean): Environment {
val environment = createEnvironment() environment.loadModule("smnp.lang")
val tokens = tokenizer.tokenize(lines) val tokens = tokenizer.tokenize(lines)
val ast = parser.parse(tokens) val ast = parser.parse(tokens)
@@ -59,16 +61,9 @@ class DefaultInterpreter : Interpreter {
return environment return environment
} }
private fun createEnvironment(): Environment { fun run(file: File, environment: Environment = DefaultEnvironment(), printTokens: Boolean = false, printAst: Boolean = false, dryRun: Boolean = false): Environment {
val environment = DefaultEnvironment()
environment.loadModule("smnp.lang")
return environment
}
fun run(file: File, printTokens: Boolean = false, printAst: Boolean = false, dryRun: Boolean = false): Environment {
val lines = file.readLines() val lines = file.readLines()
return run(lines, printTokens, printAst, dryRun) return run(lines, environment, printTokens, printAst, dryRun)
} }
override fun run(code: String) = run(code, printTokens = false, printAst = false, dryRun = false) override fun run(code: String) = run(code, printTokens = false, printAst = false, dryRun = false)