commonMain.piacenti.dslmaker.dsl.Formatter.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dsl-maker-js Show documentation
Show all versions of dsl-maker-js Show documentation
Kotlin multiplatform library to facilitate creation of DSLs with ANTLR or a simple built in parser
package piacenti.dslmaker.dsl
import piacenti.dslmaker.GenericParser2
import piacenti.dslmaker.genericRegex
import piacenti.dslmaker.structures.ASTNode
import piacenti.dslmaker.structures.Grammar
import piacenti.dslmaker.times
interface Formatter {
fun format(text: String, providedAST: ASTNode? = null): String
fun preClean(text: String): String
fun postClean(result: String): String
fun getFormatIndexes(providedAST: ASTNode?, result: String, tabText: String): Map>
fun getTabText(): String
}
abstract class GrammarBasedFormatter(val grammar: Grammar<*>, var useSpaces: Boolean = true, var numTabs: Int = 4) : Formatter {
private val parser = GenericParser2(grammar)
/**
* Supplies the indentation number to be used at ast element trimmedStartIndex. A value of 0 means no indentation
*/
abstract fun tabValueSupplier(ast: ASTNode): Pair
/**
* Flags if a line break should be added at ast element endIndex
*/
abstract fun isLineBreakable(ast: ASTNode): Pair
override fun format(text: String, providedAST: ASTNode?): String {
val tabText = getTabText()
var result = preClean(text)
val formatIndexesList = getFormatIndexes(providedAST, result, tabText)
result = TextModifier.applyModificationsMap(result, formatIndexesList)
return postClean(result)
}
override fun getTabText(): String {
val tabText = (if (useSpaces) " " else "\t") * numTabs
return tabText
}
override fun getFormatIndexes(providedAST: ASTNode?, result: String, tabText: String): Map> {
val formatIndexes = mutableMapOf>()
var tabLevel: Pair
(providedAST ?: parser.parse(result)).forEachRecursive({ astNode ->
tabLevel = tabValueSupplier(astNode)
val lineBreakable = isLineBreakable(astNode)
if (lineBreakable.first) {
formatIndexes.getOrPut(if (lineBreakable.second == Order.BEFORE) astNode.trimmedStartIndex else astNode.endIndex) { mutableListOf() }.add(TextModification("\n", lineBreakable.second))
}
if (tabLevel.first > 0) {
formatIndexes.getOrPut(if (tabLevel.second == Order.BEFORE) astNode.trimmedStartIndex else astNode.endIndex) { mutableListOf() }.add(TextModification(tabText * tabLevel.first, tabLevel.second))
}
})
return formatIndexes
}
override fun postClean(result: String) = result.trimStart().replace("\\n\\s*?\\n".toRegex(), "\n").trim()
override fun preClean(text: String) = text.replace("(?m)^\\s*".genericRegex(), "")
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy