diff --git a/app/src/main/java/com/pixelized/rplexicon/script/Script.kt b/app/src/main/java/com/pixelized/rplexicon/script/Script.kt new file mode 100644 index 0000000..7ec07be --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/script/Script.kt @@ -0,0 +1,88 @@ +package com.pixelized.rplexicon.script + +import com.pixelized.rplexicon.data.model.alteration.Alteration + +sealed class Script( + val predicate: ScriptExecutor.() -> Boolean +) { + class OR( + private vararg val scripts: Script, + ) : Script(predicate = { + scripts.any { it.predicate.invoke(this) } + }) { + override fun toString(): String { + return scripts.joinToString( + prefix = "(", + postfix = ")", + separator = " || " + ) { it.toString() } + } + } + + class AND( + private vararg val scripts: Script, + ) : Script(predicate = { + scripts.all { it.predicate.invoke(this) } + }) { + override fun toString(): String { + return scripts.joinToString( + prefix = "(", + postfix = ")", + separator = " && " + ) { it.toString() } + } + } + + class ACTIVE( + val alteration: String, + ) : Script(predicate = { + alterations.any { it.name == alteration } + }) { + override fun toString(): String { + return "ACTIVE('$alteration')" + } + } + + class ANY( + val alteration: String, + ) : Script(predicate = { + alterations.any { it.name.contains(alteration) } + }) { + override fun toString(): String { + return "ANY('$alteration')" + } + } + + class NOT( + val alteration: String, + ) : Script(predicate = { + alterations.none { it.name == alteration } + }) { + override fun toString(): String { + return "NOT('$alteration')" + } + } + + class NONE( + val alteration: String, + ) : Script(predicate = { + alterations.none { it.name.contains(alteration) } + }) { + override fun toString(): String { + return "NONE('$alteration')" + } + } + + operator fun ScriptExecutor.invoke() = predicate() +} + +class ScriptExecutor( + val alterations: List, +) + +fun scriptExecutor( + alterations: List, + block: ScriptExecutor.() -> Boolean +): Boolean { + return ScriptExecutor(alterations = alterations).run(block) +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/script/ScriptParser.kt b/app/src/main/java/com/pixelized/rplexicon/script/ScriptParser.kt new file mode 100644 index 0000000..31ff0a2 --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/script/ScriptParser.kt @@ -0,0 +1,58 @@ +package com.pixelized.rplexicon.script + +class ScriptParser { + companion object { + private val FUNCTION_REGEX = Regex("""^(\w+)\((?:(.*);(.*)|(.*))\)$""") + + private const val AND = "AND" + private const val OR = "OR" + private const val IS_ACTIVE = "ACT" + private const val ANY = "ANY" + private const val NOT = "NOT" + private const val NONE = "NONE" + + fun check(function: String, vararg params: String?, block: () -> Script): Script { + if (params.any { it.isNullOrEmpty() }) error("$function parameter malformed") + return block.invoke() + } + } + + fun parse(value: String): Script { + val result = FUNCTION_REGEX.findAll(value) + + return result.firstOrNull()?.let { matchResult -> + val (function, param1, param2, mono) = matchResult.destructured + when (function) { + AND -> check(AND, param1, param2) { Script.AND(parse(param1), parse(param2)) } + OR -> check(OR, param1, param2) { Script.OR(parse(param1), parse(param2)) } + IS_ACTIVE -> check(IS_ACTIVE, mono) { Script.ACTIVE(mono) } + ANY -> check(ANY, mono) { Script.ANY(mono) } + NOT -> check(NOT, mono) { Script.NOT(mono) } + NONE -> check(NONE, mono) { Script.NONE(mono) } + else -> error("Unrecognized function: $function") + } + } ?: error("Malformed script: should start with a function call.") + } +} + +fun main() { + val parser = ScriptParser() + val script = listOf( + """ACT(Hache de guerre en argent)""", + """ACT(Forme sauvage : Loup)""", + """ACT(Forme sauvage ; Chat)""", + """AND(ACT(Hache de guerre en argent);NOT(Bouclier))""", + """OR(AND(NOT(Hache);ACT(Épée));ACT(Bouclier))""", + """NONE(Forme sauvage)""", + ) + script.forEach { + println("Input << $it") + try { + println("Output >> ${parser.parse(it)}") + } catch (e: Exception) { + println("Output >> $e") + } finally { + println("") + } + } +} \ No newline at end of file