}
}
+@JvmInline
+value class PreProcessorScopeFilter(private val variable: String) : PreProcessorFilter {
+ override suspend fun execute(input: ParserTree, env: AsyncLexerTagEnvironment<PreProcessingContext, PreProcessingSubject>): ParserTree {
+ return env.copy(context = env.context + env.context[variable].asPreProcessorMap()).processTree(input)
+ }
+}
+
+object PreProcessorScopeInvoker : PreProcessorFilterProvider {
+ override val tagName: String = "scope"
+
+ override suspend fun provideFilter(param: String?): PreProcessorFilter? {
+ return param?.let { PreProcessorScopeFilter(it) }
+ }
+}
+
fun interface PreProcessorFilter {
suspend fun execute(input: ParserTree, env: AsyncLexerTagEnvironment<PreProcessingContext, PreProcessingSubject>): ParserTree
}
enum class PreProcessorTags(val type: PreProcessorLexerTag) {
EVAL(PreProcessorLexerTag { env, param, subNodes ->
- param?.toDoubleOrNull()?.roundToInt().requireParam("eval") { times ->
- var tree = subNodes
- repeat(times) {
- tree = env.processTree(tree)
- }
- tree
+ val times = param?.toDoubleOrNull()?.roundToInt() ?: 1
+
+ var tree = subNodes
+ repeat(times) {
+ tree = env.processTree(tree)
}
+ tree
}),
LAZY(PreProcessorLexerTag { _, param, subNodes ->
param.forbidParam("lazy") { subNodes }
env.context[env.processTree(subNodes).treeToText()]
}
}),
+ DEFAULT(PreProcessorLexerTag { env, param, subNodes ->
+ param.requireParam("var") { varName ->
+ if (varName in env.context)
+ env.context[varName]
+ else env.processTree(subNodes)
+ }
+ }),
+ SET_PARAM(PreProcessorLexerTag { env, param, subNodes ->
+ param.requireParam("var") { varName ->
+ val paramValue = env.context[varName].treeToText()
+ val withParams = subNodes.map { node ->
+ if (node is ParserTreeNode.Tag && node.param == null)
+ node.copy(param = paramValue)
+ else node
+ }
+ env.processTree(withParams)
+ }
+ }),
ENV(PreProcessorVariableInvoker),
+ SCOPE(PreProcessorScopeInvoker),
SET(PreProcessorLexerTag { env, param, subNodes ->
param.requireParam("set") { varName ->
env.context[varName] = env.processTree(subNodes)
(param?.toDoubleOrNull() ?: param?.let {
env.processTree(env.context[param]).treeToNumberOrNull(String::toDoubleOrNull)
})?.roundToInt().requireParam("index") { index ->
- inputList.getOrNull(index)
- ?.let { env.processTree(it) }
- .formatError("Index $index is not present in input list")
+ inputList.getOrNull(index).formatError("Index $index is not present in input list")
}
}),
MEMBER(PreProcessorLexerTag { env, param, subNodes ->
PreProcessorUtils.indexTree(env.processTree(subNodes), index)
}
}),
- FOREACH(PreProcessorLexerTag { env, param, subNodes ->
- param.requireParam("foreach") { itemVar ->
- val subTags = subNodes.filterIsInstance<ParserTreeNode.Tag>()
- val list = subTags.singleOrNull { it isTag "in" }?.subNodes
- ?.let { env.processTree(it) }
- ?.asPreProcessorList()
-
- val body = subTags.singleOrNull { it isTag "do" }?.subNodes
- if (list != null && body != null)
- list.mapSuspend { item ->
- PreProcessorUtils.processWithContext(env, env.context + mapOf(itemVar to item), body)
- }.flatten()
- else formatErrorToParserTree("Expected child tag [in] to take list input and child tag [do] to take loop body")
- }
+ FOR_EACH(PreProcessorLexerTag { env, param, subNodes ->
+ val itemToContext: (ParserTree) -> Map<String, ParserTree> = if (param == null)
+ ParserTree::asPreProcessorMap
+ else ({ mapOf(param to it) })
+
+ val subTags = subNodes.filterIsInstance<ParserTreeNode.Tag>()
+ val list = subTags.singleOrNull { it isTag "in" }?.subNodes
+ ?.let { env.processTree(it) }
+ ?.asPreProcessorList()
+
+ val body = subTags.singleOrNull { it isTag "do" }?.subNodes
+ if (list != null && body != null)
+ list.mapSuspend { item ->
+ PreProcessorUtils.processWithContext(env, env.context + itemToContext(item), body)
+ }.flatten()
+ else formatErrorToParserTree("Expected child tag [in] to take list input and child tag [do] to take loop body")
}),
MAP(PreProcessorLexerTag { env, param, subNodes ->
- param.requireParam("map") { itemVar ->
- val subTags = subNodes.filterIsInstance<ParserTreeNode.Tag>()
- val list = subTags.singleOrNull { it isTag "in" }?.subNodes
- ?.let { env.processTree(it) }
- ?.asPreProcessorList()
-
- val body = subTags.singleOrNull { it isTag "do" }?.subNodes
- if (list != null && body != null)
- list.mapSuspend { item ->
- ParserTreeNode.Tag("item", null, PreProcessorUtils.processWithContext(env, env.context + mapOf(itemVar to item), body))
- }
- else formatErrorToParserTree("Expected child tag [in] to take list input and child tag [do] to take loop body")
- }
+ val itemToContext: (ParserTree) -> Map<String, ParserTree> = if (param == null)
+ ParserTree::asPreProcessorMap
+ else ({ mapOf(param to it) })
+
+ val subTags = subNodes.filterIsInstance<ParserTreeNode.Tag>()
+ val list = subTags.singleOrNull { it isTag "in" }?.subNodes
+ ?.let { env.processTree(it) }
+ ?.asPreProcessorList()
+
+ val body = subTags.singleOrNull { it isTag "do" }?.subNodes
+ if (list != null && body != null)
+ list.mapSuspend { item ->
+ ParserTreeNode.Tag("item", null, PreProcessorUtils.processWithContext(env, env.context + itemToContext(item), body))
+ }
+ else formatErrorToParserTree("Expected child tag [in] to take list input and child tag [do] to take loop body")
}),
IF(PreProcessorLexerTag { env, param, subNodes ->
param.requireParam("if") { boolVar ->
}.formatError("Expected variable $boolVar to contain boolean value")
}
}),
+ LET(PreProcessorLexerTag { env, param, subNodes ->
+ param.requireParam("let") { varName ->
+ if (varName in env.context && !env.context[varName].isNull())
+ env.processTree(subNodes)
+ else emptyList()
+ }
+ }),
+ FALLBACK(PreProcessorLexerTag { env, param, subNodes ->
+ param.requireParam("fallback") { varName ->
+ if (varName !in env.context || env.context[varName].isNull())
+ env.processTree(subNodes)
+ else emptyList()
+ }
+ }),
MATH(PreProcessorMathOperators),
LOGIC(PreProcessorLogicOperator),
TEST(PreProcessorInputTest),
}),
FUNCTION(PreProcessorLexerTag { env, param, subNodes ->
param.requireParam("function") { scriptName ->
- PreProcessorScriptLoader.runScriptSafe(scriptName, subNodes.asPreProcessorMap(), env) {
+ PreProcessorScriptLoader.runScriptSafe(scriptName, env.processTree(subNodes).asPreProcessorMap(), env) {
it.renderInBBCode()
}
}
}),
FILTER(PreProcessorLexerTag { env, param, subNodes ->
param.requireParam("filter") { scriptName ->
- PreProcessorScriptLoader.runScriptSafe(scriptName, subNodes, env) {
+ PreProcessorScriptLoader.runScriptSafe(scriptName, env.processTree(subNodes), env) {
it.renderInBBCode()
}
}
}
}
}),
- IMPORT(PreProcessorLexerTag { _, param, subNodes ->
+ IMPORT(PreProcessorLexerTag { env, param, subNodes ->
param.requireParam("import") { templateName ->
- PreProcessorTemplateLoader.runTemplateWith(templateName, subNodes.asPreProcessorMap())
+ PreProcessorTemplateLoader.runTemplateWith(templateName, env.processTree(subNodes).asPreProcessorMap())
}
}),
INCLUDE(PreProcessorLexerTag { env, param, subNodes ->
}
}),
TEMPLATE(PreProcessorLexerTag { env, param, subNodes ->
- param.forbidParam("include") {
+ param.forbidParam("template") {
PreProcessorTemplateLoader.loadTemplate(env.processTree(subNodes).treeToText())
}
}),