Rework indirect tag code
authorLanius Trolling <lanius@laniustrolling.dev>
Wed, 6 Mar 2024 23:41:43 +0000 (18:41 -0500)
committerLanius Trolling <lanius@laniustrolling.dev>
Wed, 6 Mar 2024 23:41:43 +0000 (18:41 -0500)
src/jvmMain/kotlin/info/mechyrdia/lore/parser.kt

index d3379c1c2c3daa8c3fa02cf12aeabf73c80d7076..26ea99d097fa1a9b8d0f64dc05cc2f527000d67c 100644 (file)
@@ -10,16 +10,9 @@ class TextParserInternalState {
        var suppressEndParagraph: Boolean = false
 }
 
-sealed class InsideTag {
-       abstract val tag: String
-       
-       data class DirectTag(override val tag: String) : InsideTag()
-       data class IndirectTag(override val tag: String, val param: String?) : InsideTag()
-}
-
 sealed class TextParserState<TContext>(
        val scope: TextParserScope<TContext>,
-       val insideTags: List<InsideTag>,
+       val insideTags: List<String>,
        protected val internalState: TextParserInternalState,
 ) {
        abstract fun processCharacter(char: Char): TextParserState<TContext>
@@ -28,16 +21,7 @@ sealed class TextParserState<TContext>(
        protected fun appendText(text: String) {
                if (text.isEmpty()) return
                
-               scope.write.append(
-                       insideTags.foldRight(censorText(text)) { insideTag, t ->
-                               if (insideTag is InsideTag.IndirectTag) {
-                                       val (tag, param) = insideTag
-                                       (scope.tags[tag] as? TextParserTagType.Indirect<TContext>)
-                                               ?.process(param, t, scope.ctx)
-                                               ?: "[$tag${param?.let { "=$it" } ?: ""}]$t[/$tag]"
-                               } else t
-                       }
-               )
+               scope.write.append(censorText(text))
                internalState.suppressEndParagraph = false
        }
        
@@ -49,7 +33,7 @@ sealed class TextParserState<TContext>(
        }
        
        protected fun nextParagraph() {
-               val newline = if (insideTags.none { it is InsideTag.DirectTag }) {
+               val newline = if (insideTags.isEmpty()) {
                        if (internalState.suppressEndParagraph)
                                "<p>"
                        else
@@ -89,7 +73,7 @@ sealed class TextParserState<TContext>(
                }
        }
        
-       class PlainText<TContext>(scope: TextParserScope<TContext>, private val text: String, insideTags: List<InsideTag>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
+       class PlainText<TContext>(scope: TextParserScope<TContext>, private val text: String, insideTags: List<String>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
                override fun processCharacter(char: Char): TextParserState<TContext> {
                        return if (char == '[') {
                                appendText(text)
@@ -111,7 +95,7 @@ sealed class TextParserState<TContext>(
                }
        }
        
-       class NoFormatText<TContext>(scope: TextParserScope<TContext>, private val text: String, insideTags: List<InsideTag>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
+       class NoFormatText<TContext>(scope: TextParserScope<TContext>, private val text: String, insideTags: List<String>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
                override fun processCharacter(char: Char): TextParserState<TContext> {
                        val newText = text + char
                        return if (newText.endsWith("[/$NO_FORMAT_TAG]")) {
@@ -132,7 +116,28 @@ sealed class TextParserState<TContext>(
                }
        }
        
-       class OpenTag<TContext>(scope: TextParserScope<TContext>, private val tag: String, insideTags: List<InsideTag>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
+       class InsideIndirectTag<TContext>(scope: TextParserScope<TContext>, private val tagName: String, private val tagType: TextParserTagType.Indirect<TContext>, private val param: String?, private val text: String, insideTags: List<String>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
+               override fun processCharacter(char: Char): TextParserState<TContext> {
+                       val newText = text + char
+                       return if (newText.endsWith("[/$tagName]")) {
+                               appendTextRaw(tagType.process(param, censorText(newText.removeSuffix("[/$tagName]")), scope.ctx))
+                               
+                               if (tagType.isBlock)
+                                       cancelEndParagraph()
+                               
+                               PlainText(scope, "", insideTags, internalState)
+                       } else
+                               InsideIndirectTag(scope, tagName, tagType, param, newText, insideTags, internalState)
+               }
+               
+               override fun processEndOfText() {
+                       appendTextRaw(tagType.process(param, censorText(text), scope.ctx))
+                       if (text.isNotBlank())
+                               lastParagraph()
+               }
+       }
+       
+       class OpenTag<TContext>(scope: TextParserScope<TContext>, private val tag: String, insideTags: List<String>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
                override fun processCharacter(char: Char): TextParserState<TContext> {
                        return if (char == ']') {
                                if (tag.equals(NO_FORMAT_TAG, ignoreCase = true))
@@ -145,10 +150,10 @@ sealed class TextParserState<TContext>(
                                        when (tagType) {
                                                is TextParserTagType.Direct<TContext> -> {
                                                        appendTextRaw(tagType.begin(null, scope.ctx))
-                                                       PlainText(scope, "", insideTags + InsideTag.DirectTag(tag), internalState)
+                                                       PlainText(scope, "", insideTags + tag, internalState)
                                                }
                                                
-                                               is TextParserTagType.Indirect<TContext> -> PlainText(scope, "", insideTags + InsideTag.IndirectTag(tag, null), internalState)
+                                               is TextParserTagType.Indirect<TContext> -> InsideIndirectTag(scope, tag, tagType, null, "", insideTags, internalState)
                                                
                                                else -> PlainText(scope, "[$tag]", insideTags, internalState)
                                        }
@@ -167,7 +172,7 @@ sealed class TextParserState<TContext>(
                }
        }
        
-       class TagParam<TContext>(scope: TextParserScope<TContext>, private val tag: String, private val param: String, insideTags: List<InsideTag>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
+       class TagParam<TContext>(scope: TextParserScope<TContext>, private val tag: String, private val param: String, insideTags: List<String>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
                override fun processCharacter(char: Char): TextParserState<TContext> {
                        return if (char == ']') {
                                val tagType = scope.tags[tag]
@@ -177,10 +182,10 @@ sealed class TextParserState<TContext>(
                                when (tagType) {
                                        is TextParserTagType.Direct<TContext> -> {
                                                appendTextRaw(tagType.begin(param, scope.ctx))
-                                               PlainText(scope, "", insideTags + InsideTag.DirectTag(tag), internalState)
+                                               PlainText(scope, "", insideTags + tag, internalState)
                                        }
                                        
-                                       is TextParserTagType.Indirect<TContext> -> PlainText(scope, "", insideTags + InsideTag.IndirectTag(tag, param), internalState)
+                                       is TextParserTagType.Indirect<TContext> -> InsideIndirectTag(scope, tag, tagType, param, "", insideTags, internalState)
                                        
                                        else -> PlainText(scope, "[$tag=$param]", insideTags, internalState)
                                }
@@ -194,15 +199,12 @@ sealed class TextParserState<TContext>(
                }
        }
        
-       class CloseTag<TContext>(scope: TextParserScope<TContext>, private val tag: String, insideTags: List<InsideTag>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
+       class CloseTag<TContext>(scope: TextParserScope<TContext>, private val tag: String, insideTags: List<String>, internalState: TextParserInternalState) : TextParserState<TContext>(scope, insideTags, internalState) {
                override fun processCharacter(char: Char): TextParserState<TContext> {
                        return if (char == ']') {
                                val tagType = scope.tags[tag]
-                               val nextState = if (tagType is TextParserTagType.Direct<TContext> && insideTags.lastOrNull()?.tag == tag) {
+                               val nextState = if (tagType is TextParserTagType.Direct<TContext> && insideTags.lastOrNull() == tag) {
                                        appendTextRaw(tagType.end(scope.ctx))
-                                       
-                                       PlainText(scope, "", insideTags.dropLast(1), internalState)
-                               } else if (insideTags.isNotEmpty() && (insideTags.last() as? InsideTag.IndirectTag)?.tag == tag) {
                                        PlainText(scope, "", insideTags.dropLast(1), internalState)
                                } else {
                                        appendText("[/$tag]")