Skip to content

Commit

Permalink
feat: create xml parser in Kotlin
Browse files Browse the repository at this point in the history
  • Loading branch information
vighnesh153 committed Sep 8, 2024
1 parent 0d5e250 commit 2ce2aa9
Show file tree
Hide file tree
Showing 11 changed files with 1,317 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package dev.vighnesh153.xml.formatter.ast

import dev.vighnesh153.xml.formatter.lexer.Token

class XmlCommentNode(val comment: Token) : XmlExpression {
override fun toString(indentation: Int): String {
return "${buildIndentation(indentation)}<!-- ${comment.tokenLiteral.trim()} -->"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package dev.vighnesh153.xml.formatter.ast

import dev.vighnesh153.xml.formatter.lexer.Token

class XmlElementAttribute(
val namespaces: List<Token>,
val value: Token,
) {
override fun toString(): String {
val key = namespaces.joinToString(":") { it.tokenLiteral }
return "$key=\"${value.tokenLiteral}\""
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package dev.vighnesh153.xml.formatter.ast

sealed interface XmlExpression {
fun toString(indentation: Int): String
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package dev.vighnesh153.xml.formatter.ast

class XmlProgram : XmlExpression {
private val mutableStatements = mutableListOf<XmlExpression>()
val statements: List<XmlExpression>
get() = mutableStatements.toList()

fun addStatement(stmt: XmlExpression) {
mutableStatements.add(stmt)
}

override fun toString(indentation: Int): String =
mutableStatements.joinToString("\n") { it.toString(indentation) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package dev.vighnesh153.xml.formatter.ast

class XmlPrologNode : XmlExpression {
private val mutableAttributes = mutableListOf<XmlElementAttribute>()
val attributes: List<XmlElementAttribute>
get() = mutableAttributes.toList()

fun addAttribute(attr: XmlElementAttribute) {
mutableAttributes.add(attr)
}

override fun toString(indentation: Int): String {
val builder = StringBuilder()
builder.append(buildIndentation(indentation))
builder.append("<?xml")
for (attr in mutableAttributes) {
builder.append(" ")
builder.append(attr.toString())
}
builder.append("?>")
return builder.toString()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package dev.vighnesh153.xml.formatter.ast

import dev.vighnesh153.xml.formatter.lexer.Token

class XmlTagNode(
) : XmlExpression {
private val mutableNamespaces = mutableListOf<Token>()
val namespaces: List<Token>
get() = mutableNamespaces.toList()

private val mutableAttributes = mutableListOf<XmlElementAttribute>()
val attributes: List<XmlElementAttribute>
get() = mutableAttributes.toList()

private val mutableChildren = mutableListOf<XmlExpression>()
val children: List<XmlExpression>
get() = mutableChildren.toList()

fun addNamespace(ns: Token) {
mutableNamespaces.add(ns)
}

fun addAttribute(attr: XmlElementAttribute) {
mutableAttributes.add(attr)
}

fun addChild(child: XmlExpression) {
mutableChildren.add(child)
}

override fun toString(indentation: Int): String {
val builder = mutableListOf<String>()

val tag = mutableNamespaces.joinToString(":") { it.tokenLiteral }

builder.add("${buildIndentation(indentation)}<$tag")
if (mutableAttributes.size == 1) {
val serializedAttrs = mutableAttributes.joinToString(" ") { it.toString() }
builder[builder.lastIndex] += " $serializedAttrs"
} else if (mutableAttributes.size > 1) {
for (attr in mutableAttributes) {
builder.add("${buildIndentation(indentation + 1)}$attr")
}
}

if (mutableChildren.isEmpty()) {
builder[builder.lastIndex] += " />"
} else {
builder[builder.lastIndex] += ">"
}

// if only a single text node child
if (mutableChildren.size == 1 && mutableChildren.first() is XmlTextNode) {
return builder.joinToString("\n") + mutableChildren.first()
.toString(0) + "</$tag>"
}

for (child in mutableChildren) {
builder.add(child.toString(indentation + 1))
}

if (mutableChildren.isNotEmpty()) {
builder.add("${buildIndentation(indentation)}</$tag>")
}

return builder.joinToString("\n")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package dev.vighnesh153.xml.formatter.ast

import dev.vighnesh153.xml.formatter.lexer.Token

class XmlTextNode(val text: Token) : XmlExpression {
override fun toString(indentation: Int): String {
return "${buildIndentation(indentation)}${text.tokenLiteral.trim()}"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package dev.vighnesh153.xml.formatter.ast

internal fun buildIndentation(indentation: Int): String = " ".repeat(indentation * 4)
Loading

0 comments on commit 2ce2aa9

Please sign in to comment.