All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.skillw.asahi.internal.lexer.AsahiLexerImpl.kt Maven / Gradle / Ivy

There is a newer version: 1.6.7-beta-6
Show newest version
package com.skillw.asahi.internal.lexer

import com.skillw.asahi.api.AsahiAPI.compile
import com.skillw.asahi.api.AsahiManager
import com.skillw.asahi.api.member.lexer.AsahiLexer
import com.skillw.asahi.api.member.lexer.tokenizer.ScriptTokenizer
import com.skillw.asahi.api.member.namespace.NamespaceContainer
import com.skillw.asahi.api.member.quest.Quester
import com.skillw.asahi.api.questSafely
import com.skillw.asahi.api.quester
import com.skillw.asahi.api.script.AsahiCompiledScript
import com.skillw.asahi.api.script.AsahiQuestException
import com.skillw.asahi.util.condition.calcCondition
import com.skillw.pouvoir.util.condition.ConditionOperator.Companion.isConditionOperator
import com.skillw.pouvoir.util.condition.ConditionOperator.Companion.toConditionOperator
import com.skillw.pouvoir.util.script.MessageUtil


/**
 * AsahiLexerImpl
 *
 * @constructor
 */
internal class AsahiLexerImpl : AsahiLexer {
    private var index = -1
    override val namespaces = NamespaceContainer()

    //组合优先于继承
    private val tokenizer: ScriptTokenizer
    private val tokens
        get() = tokenizer.tokens()

    private constructor(origin: String) {
        tokenizer = ScriptTokenizer.of(AsahiManager.replace(origin))
    }

    private constructor(lexer: AsahiLexerImpl) {
        tokenizer = lexer.tokenizer
    }

    private constructor(tokens: Collection) {
        tokenizer = ScriptTokenizer.of(tokens)
    }

    companion object {
        @JvmStatic
        fun of(script: String): AsahiLexerImpl {
            return AsahiLexerImpl(script)
        }

        @JvmStatic
        fun of(tokens: Collection): AsahiLexerImpl {
            return AsahiLexerImpl(tokens)
        }
    }

    /**
     * Except
     *
     * @param expects
     * @return
     */
    override fun expect(vararg expects: String): Boolean {
        return expects.any {
            (peekNextIgnoreBlank() == it).also { bool ->
                if (bool) {
                    next()
                    return@any true
                }
            }
        }
    }


    /**
     * Has next
     *
     * @return
     */
    override fun hasNext(): Boolean {
        val last = peek() == "\n" && index + 1 == tokens.lastIndex
        return index + 1 < tokens.size && !last
    }

    override fun current(): String {
        return tokens[index]
    }

    /**
     * Next
     *
     * @return
     */
    override fun next(): String {
        return tokens.getOrNull(++index).run { if (this == "\n") next() else this } ?: kotlin.run { index--;null }
        ?: error("Has no next")
    }

    override fun previous(): String? {
        if (index - 1 <= 0) {
            return null
        }
        return tokens[--index]
    }

    override fun currentIndex(): Int {
        return index
    }

    override fun peekNextIgnoreBlank(): String? {
        return tokens.getOrNull(index + 1)?.run {
            ifBlank {
                index++
                return peekNextIgnoreBlank().also { index-- }
            }
        }
    }

    override fun peek(): String? {
        return tokens.getOrNull(index + 1)
    }

    override fun skipTill(from: String, till: String): Boolean {
        var countIf = 0
        while (hasNext()) {
            when (next()) {
                from -> countIf++
                till -> if (--countIf <= 0) return true
                else -> {}
            }
        }
        return false
    }

    private fun trulyNext(): String = tokens[++index]

    override fun splitTill(from: String, to: String): ArrayList {
        var count = if (tokens.getOrNull(currentIndex()) == "{") 1 else 0
        val tokens = ArrayList()
        while (hasNext()) {
            when (val next = trulyNext()) {
                from ->
                    if (count++ == 0) {
                        continue
                    } else tokens.add(next)

                to -> if (--count <= 0) return tokens else tokens.add(next)
                else -> tokens.add(next)
            }
        }
        return tokens
    }

    override fun splitBefore(vararg to: String): ArrayList {
        val tokens = ArrayList()
        while (hasNext()) {
            if (peek() in to) {
                return tokens
            }
            tokens.add(trulyNext())
        }
        return tokens
    }

    override fun splitBeforeString(vararg to: String): String {
        val builder = StringBuilder()
        while (hasNext()) {
            if (peek() in to) {
                return builder.toString()
            }
            builder.append(" ${trulyNext()}")
        }
        return builder.toString()
    }

    override fun reset() {
        index = -1
    }

    override fun info(message: String, index: Int): String {
        return tokenizer.info(message, index)
    }

    override fun withEach(receiver: String.(Int) -> Unit) {
        while (hasNext()) {
            next().run { receiver(currentIndex()) }
        }
    }

    override fun questCondition(
        vararg till: String,
        boolQuester: AsahiLexer.() -> Quester,
    ): Quester {
        val conditions = ArrayList>()
        while (hasNext()) {
            if (peek() in till) break
            if (peek()?.isConditionOperator() == true) {
                conditions.add(next().toConditionOperator().let { quester { it } })
                continue
            }
            conditions.add(boolQuester())
        }
        return quester { conditions.map { it.get() }.calcCondition() }
    }

    override fun error(message: String): Nothing {
        throw AsahiQuestException(info(message))
    }

    private var debug = false

    override fun debugOn() {
        debug = true
    }

    override fun debugOff() {
        debug = false
    }

    private fun debug() {
        if (debug) {
            MessageUtil.debug(info("Compile Debug-${currentIndex()}"))
        }
    }

    override fun questAllTo(script: AsahiCompiledScript) {
        while (hasNext()) {
            debug()
            script.add(questSafely())
        }
        debug()
        debugOff()
    }

    override fun parseScript(vararg namespaces: String): AsahiCompiledScript {
        return splitTill("{", "}").compile(*namespaces, *namespaceNames())
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy