先読みに対応してコードブロック後の装飾に対応

This commit is contained in:
usbharu 2024-11-14 14:19:12 +09:00
parent b61a40ea32
commit 3ad0cd6f92
Signed by: usbharu
GPG Key ID: 8CB1087135660B8D
3 changed files with 46 additions and 22 deletions

View File

@ -64,18 +64,13 @@ class Lexer {
if (iterator.peekOrNull() == '[') { if (iterator.peekOrNull() == '[') {
tokens.add(Exclamation) tokens.add(Exclamation)
} else { } else {
tokens.add(Text("!")) addText(tokens, "!")
} }
} }
else -> { else -> {
val lastToken = tokens.lastOrNull() addText(tokens, next.toString())
if (lastToken is Text) {
lastToken.text += next.toString()
} else {
tokens.add(Text(next.toString()))
}
} }
} }
if (!inline && tokens.lastOrNull() !is Whitespace) { //行頭が空白の場合は一旦無視する if (!inline && tokens.lastOrNull() !is Whitespace) { //行頭が空白の場合は一旦無視する
@ -105,13 +100,22 @@ class Lexer {
return tokens return tokens
} }
private fun addText(tokens: MutableList<Token>, next: String) {
val lastToken = tokens.lastOrNull()
if (lastToken is Text) {
lastToken.text += next
} else {
tokens.add(Text(next))
}
}
private fun codeblock( private fun codeblock(
iterator: PeekableCharIterator, iterator: PeekableCharIterator,
next: Char, next: Char,
tokens: MutableList<Token>, tokens: MutableList<Token>,
inCode: Boolean, inCode: Boolean,
codeBuffer: StringBuilder, codeBuffer: StringBuilder,
inline: Boolean inline: Boolean,
): Boolean { ): Boolean {
var inCode1 = inCode var inCode1 = inCode
if (iterator.peekOrNull() == next && !inline) { //行頭かつ次の文字が` if (iterator.peekOrNull() == next && !inline) { //行頭かつ次の文字が`
@ -157,20 +161,16 @@ class Lexer {
} }
} else { } else {
val codeBuilder = StringBuilder() val peekString = peekString(next, iterator)
while (iterator.hasNext() && iterator.peekOrNull() != next) { if (peekString != null && peekString.isEmpty()) {
codeBuilder.append(iterator.next()) addText(tokens, "$next$next")
} iterator.next()
if (iterator.hasNext() && iterator.next() == next) { //インラインコードブロックかと思ったら違った } else if (peekString != null) {
if (codeBuilder.isEmpty()) { tokens.add(InlineCodeBlock(peekString))
tokens.add(Text("$next$next")) iterator.skip(peekString.length + 1)
} else { } else {
tokens.add(InlineCodeBlock(codeBuilder.toString())) addText(tokens, next.toString())
} }
} else {
tokens.add(Text(codeBuilder.insert(0, next).toString()))
}
} }
return inCode1 return inCode1
} }
@ -345,6 +345,19 @@ class Lexer {
return count return count
} }
fun peekString(char: Char, iterator: PeekableCharIterator): String? {
var counter = 0
val stringBuilder = StringBuilder()
while (iterator.peekOrNull(counter) != null && iterator.peekOrNull(counter) != char) {
stringBuilder.append(iterator.peekOrNull(counter))
counter++
}
if (iterator.peekOrNull(counter) == null) {
return null
}
return stringBuilder.toString()
}
fun collect(iterator: PeekableCharIterator): String { fun collect(iterator: PeekableCharIterator): String {
val char = mutableListOf<Char>() val char = mutableListOf<Char>()
while (iterator.hasNext()) { while (iterator.hasNext()) {

View File

@ -15,6 +15,12 @@ class PeekableCharIterator(private val charArray: CharArray) : Iterator<Char> {
fun peekOrNull(): Char? = charArray.getOrNull(index) fun peekOrNull(): Char? = charArray.getOrNull(index)
fun current(): Int = index fun current(): Int = index
fun peekOrNull(offset: Int): Char? = charArray.getOrNull(index + offset)
fun skip(count: Int = 0) {
index += count
}
} }
class PeekableStringIterator(private val list: List<String>) : Iterator<String> { class PeekableStringIterator(private val list: List<String>) : Iterator<String> {

View File

@ -756,7 +756,7 @@ class LexerTest {
assertContentEquals( assertContentEquals(
listOf( listOf(
Text("```"), Text("`aiueo") Text("````aiueo")
), actual ), actual
) )
} }
@ -816,7 +816,12 @@ class LexerTest {
assertContentEquals( assertContentEquals(
listOf( listOf(
Text("aiueo"), Whitespace(1, ' '), Text("```abcd") Text("aiueo"),
Whitespace(1, ' '),
Text("```abcd"),
Asterisk(1, '*'),
Text("a"),
Asterisk(1, '*')
), actual ), actual
) )
} }