diff --git a/src/main/kotlin/io/smnp/data/signature/ArgumentsList.kt b/src/main/kotlin/io/smnp/data/signature/ArgumentsList.kt new file mode 100644 index 0000000..ef96622 --- /dev/null +++ b/src/main/kotlin/io/smnp/data/signature/ArgumentsList.kt @@ -0,0 +1,21 @@ +package io.smnp.data.signature + +import io.smnp.data.model.Value + +class ArgumentsList(val isValid: Boolean, val arguments: List) { + operator fun get(index: Int) = arguments[index] + + fun toArray() = arguments.toTypedArray() + + override fun toString() = if(isValid) "valid($arguments)" else "invalid" + + companion object { + fun valid(arguments: List): ArgumentsList { + return ArgumentsList(true, arguments) + } + + fun invalid(): ArgumentsList { + return ArgumentsList(false, emptyList()) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/io/smnp/data/signature/Matcher.kt b/src/main/kotlin/io/smnp/data/signature/Matcher.kt index 3e7a491..22573a6 100644 --- a/src/main/kotlin/io/smnp/data/signature/Matcher.kt +++ b/src/main/kotlin/io/smnp/data/signature/Matcher.kt @@ -3,7 +3,7 @@ package io.smnp.data.signature import io.smnp.data.enumeration.DataType import io.smnp.data.model.Value -class Matcher(val type: DataType?, val matcher: (Value) -> Boolean, val string: String) { +class Matcher(val type: DataType?, private val matcher: (Value) -> Boolean, private val string: String, val optional: Boolean = false) { fun match(value: Value): Boolean = (type != null && type == value.type && matcher(value)) || (type == null) && matcher(value) @@ -31,6 +31,10 @@ class Matcher(val type: DataType?, val matcher: (Value) -> Boolean, val string: override fun toString() = string companion object { + fun optional(matcher: Matcher): Matcher { + return Matcher(matcher.type, matcher.matcher, "${matcher.string}?", true) + } + fun mapOfMatchers(keyMatchers: List, valueMatchers: List): Matcher { return Matcher( DataType.MAP, diff --git a/src/main/kotlin/io/smnp/data/signature/Signature.kt b/src/main/kotlin/io/smnp/data/signature/Signature.kt new file mode 100644 index 0000000..c418405 --- /dev/null +++ b/src/main/kotlin/io/smnp/data/signature/Signature.kt @@ -0,0 +1,17 @@ +package io.smnp.data.signature + +import io.smnp.data.model.Value + +interface Signature { + fun parse(arguments: List): ArgumentsList + + companion object { + fun simple(vararg signature: Matcher): Signature { + return SimpleSignature(*signature) + } + + fun vararg(varargMatcher: Matcher, vararg signature: Matcher): Signature { + return VarargSignature(varargMatcher, *signature) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/io/smnp/data/signature/SimpleSignature.kt b/src/main/kotlin/io/smnp/data/signature/SimpleSignature.kt new file mode 100644 index 0000000..ce9f4bf --- /dev/null +++ b/src/main/kotlin/io/smnp/data/signature/SimpleSignature.kt @@ -0,0 +1,15 @@ +package io.smnp.data.signature + +import io.smnp.data.model.Value + +class SimpleSignature(private vararg val signature: Matcher) : Signature { + override fun parse(arguments: List): ArgumentsList { + if (arguments.size > signature.size || arguments.size < signature.count { !it.optional }) { + return ArgumentsList.invalid() + } + + return ArgumentsList(signature.zip(arguments).all { (matcher, argument) -> matcher.match(argument) }, arguments) + } + + override fun toString() = "(${signature.joinToString(", ")})" +} \ No newline at end of file diff --git a/src/main/kotlin/io/smnp/data/signature/VarargSignature.kt b/src/main/kotlin/io/smnp/data/signature/VarargSignature.kt new file mode 100644 index 0000000..1fda364 --- /dev/null +++ b/src/main/kotlin/io/smnp/data/signature/VarargSignature.kt @@ -0,0 +1,41 @@ +package io.smnp.data.signature + +import io.smnp.data.model.Value + +class VarargSignature(private val varargMatcher: Matcher, private vararg val signature: Matcher) : Signature { + override fun parse(arguments: List): ArgumentsList { + if ((arrayListOf(varargMatcher) + signature).any { it.optional }) { + throw RuntimeException("Vararg signature does not support optional arguments") + } + + if (signature.size > arguments.size) { + return ArgumentsList.invalid() + } + + for (i in signature.indices) { + if (!signature[i].match(arguments[i])) { + return ArgumentsList.invalid() + } + } + + for (i in signature.size until arguments.size) { + if (!varargMatcher.match(arguments[i])) { + return ArgumentsList.invalid() + } + } + + return ArgumentsList.valid( + arguments.subList(0, signature.size) + listOf( + Value.list( + arguments.subList( + signature.size, + arguments.size + ) + ) + ) + ) + } + + override fun toString() = + "(${signature.joinToString(", ")}${if (signature.isNotEmpty()) ", " else ""}...$varargMatcher)" +} \ No newline at end of file