From 0a972cb8eb4a2320523505abf34376eee787db07 Mon Sep 17 00:00:00 2001 From: usbharu Date: Wed, 13 Nov 2024 12:02:21 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20when=E3=81=AE=E6=9B=B8=E3=81=8D?= =?UTF-8?q?=E6=96=B9=E3=82=92=E5=A4=89=E6=9B=B4=E3=81=97=E3=82=A2=E3=82=B9?= =?UTF-8?q?=E3=82=BF=E3=83=AA=E3=82=B9=E3=82=AF=E3=81=AB=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/dev/usbharu/markdown/Lexer.kt | 118 ++++++++++-------- .../kotlin/dev/usbharu/markdown/Token.kt | 3 +- .../kotlin/dev/usbharu/markdown/LexerTest.kt | 35 ++++++ 3 files changed, 103 insertions(+), 53 deletions(-) diff --git a/library/src/commonMain/kotlin/dev/usbharu/markdown/Lexer.kt b/library/src/commonMain/kotlin/dev/usbharu/markdown/Lexer.kt index 853fb69..dedd93c 100644 --- a/library/src/commonMain/kotlin/dev/usbharu/markdown/Lexer.kt +++ b/library/src/commonMain/kotlin/dev/usbharu/markdown/Lexer.kt @@ -6,6 +6,9 @@ class Lexer { fun lex(input: String): List { val tokens = mutableListOf() val lines = PeekableStringIterator(input.lines()) + + var inQuote = false + line@ while (lines.hasNext()) { if (lines.peekOrNull() == "") { @@ -15,10 +18,15 @@ class Lexer { val iterator = PeekableCharIterator(line.toCharArray()) char@ while (iterator.hasNext()) { - when (val next = iterator.next()) { - '#', '#' -> header(iterator, tokens) - '>', '>' -> quote(iterator, tokens) - '-', '=', 'ー', '=' -> { + val next = iterator.next() + when { + next == '#' || next == '#' -> header(iterator, tokens) + (next == '>' || next == '>') && !inQuote -> { + inQuote = true + quote(iterator, tokens) + } + + next == '-' || next == '=' || next == 'ー' || next == '=' -> { if (iterator.peekOrNull()?.isWhitespace() == true) { //-の直後がスペースならリストの可能性 list(iterator, tokens) } else {//それ以外ならセパレーターの可能性 @@ -26,56 +34,35 @@ class Lexer { } } - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> + next in '0'..'9' || next in '0'..'9' -> decimalList(iterator, tokens, next) - '[', '「' -> { - tokens.add(SquareBracketStart) - } + next == '[' || next == '「' -> tokens.add(SquareBracketStart) - ']', '」' -> { - tokens.add(SquareBracketEnd) - } + next == ']' || next == '」' -> tokens.add(SquareBracketEnd) - '(', '(' -> { - tokens.add(ParenthesesStart) - } + next == '(' || next == '(' -> tokens.add(ParenthesesStart) - ')', ')' -> { - tokens.add(ParenthesesEnd) - } + next == ')' || next == ')' -> tokens.add(ParenthesesEnd) - ' ', ' ' -> { - tokens.add(Whitespace(skipWhitespace(iterator) + 1, next)) //nextの分1足す - } + next.isWhitespace() -> tokens.add( + Whitespace( + skipWhitespace(iterator) + 1, + next + ) + ) //nextの分1足す - 'h' -> { - //todo httpにも対応 - val charIterator = "ttps://".iterator() - val urlBuilder = StringBuilder() - urlBuilder.append(next) - while (charIterator.hasNext() && iterator.hasNext()) { - val nextC = charIterator.next() - val nextC2 = iterator.next() - urlBuilder.append(nextC2) - if (nextC != nextC2) { - tokens.add(Text(urlBuilder.toString())) - continue@char - } + next == 'h' -> url(next, iterator, tokens) + + next == '*' -> { + var count = 1 + while (iterator.peekOrNull() == '*') { + count++ + iterator.next() } - if (urlBuilder.length == 1) { - tokens.add(Text(urlBuilder.toString())) //hだけのときはURLじゃないのでテキストとして追加 - } else { - while (iterator.hasNext() && iterator.peekOrNull()?.isWhitespace() != true) { - urlBuilder.append(iterator.next()) - } - tokens.add(Url(urlBuilder.toString())) - } - - + tokens.add(Asterisk(count)) } - else -> { val lastToken = tokens.lastOrNull() if (lastToken is Text) { @@ -89,7 +76,7 @@ class Lexer { tokens.add(Break(1)) } - + inQuote = false } println(tokens) @@ -104,10 +91,38 @@ class Lexer { return tokens } + private fun url( + next: Char, + iterator: PeekableCharIterator, + tokens: MutableList, + ) { + //todo httpにも対応 + val charIterator = "ttps://".iterator() + val urlBuilder = StringBuilder() + urlBuilder.append(next) + while (charIterator.hasNext() && iterator.hasNext()) { + val nextC = charIterator.next() + val nextC2 = iterator.next() + urlBuilder.append(nextC2) + if (nextC != nextC2) { + tokens.add(Text(urlBuilder.toString())) + return + } + } + if (urlBuilder.length == 1) { + tokens.add(Text(urlBuilder.toString())) //hだけのときはURLじゃないのでテキストとして追加 + } else { + while (iterator.hasNext() && iterator.peekOrNull()?.isWhitespace() != true) { + urlBuilder.append(iterator.next()) + } + tokens.add(Url(urlBuilder.toString())) + } + } + private fun decimalList( iterator: PeekableCharIterator, tokens: MutableList, - next: Char + next: Char, ) { val comma = iterator.peekOrNull() if (comma == null) { @@ -127,7 +142,7 @@ class Lexer { private fun list( iterator: PeekableCharIterator, - tokens: MutableList + tokens: MutableList, ) { if (iterator.peekOrNull()?.isWhitespace() == true) { @@ -159,7 +174,7 @@ class Lexer { private fun separator( next: Char, iterator: PeekableCharIterator, - tokens: MutableList + tokens: MutableList, ) { val builder = StringBuilder() builder.append(next) @@ -181,7 +196,7 @@ class Lexer { private fun quote( iterator: PeekableCharIterator, - tokens: MutableList + tokens: MutableList, ) { var count = 1 while (iterator.peekOrNull()?.isWhitespace() == false) { @@ -190,12 +205,11 @@ class Lexer { } tokens.add(Quote(count)) skipWhitespace(iterator) - tokens.add(Text(collect(iterator))) } private fun header( iterator: PeekableCharIterator, - tokens: MutableList + tokens: MutableList, ) { var count = 1 while (iterator.peekOrNull()?.isWhitespace() == false) { @@ -229,7 +243,7 @@ class Lexer { */ private fun blankLine( lines: PeekableStringIterator, - tokens: MutableList + tokens: MutableList, ) { var count = 0 while (lines.peekOrNull() == "") { diff --git a/library/src/commonMain/kotlin/dev/usbharu/markdown/Token.kt b/library/src/commonMain/kotlin/dev/usbharu/markdown/Token.kt index 6223a06..36ff4a2 100644 --- a/library/src/commonMain/kotlin/dev/usbharu/markdown/Token.kt +++ b/library/src/commonMain/kotlin/dev/usbharu/markdown/Token.kt @@ -22,4 +22,5 @@ data object SquareBracketStart : Token() data object SquareBracketEnd : Token() data object ParenthesesStart : Token() data object ParenthesesEnd : Token() -data class Url(var url: String) : Token() \ No newline at end of file +data class Url(var url: String) : Token() +data class Asterisk(var count: Int) : Token() \ No newline at end of file diff --git a/library/src/commonTest/kotlin/dev/usbharu/markdown/LexerTest.kt b/library/src/commonTest/kotlin/dev/usbharu/markdown/LexerTest.kt index fc2cbb1..21114e4 100644 --- a/library/src/commonTest/kotlin/dev/usbharu/markdown/LexerTest.kt +++ b/library/src/commonTest/kotlin/dev/usbharu/markdown/LexerTest.kt @@ -483,4 +483,39 @@ class LexerTest { ), actual ) } + + @Test + fun アスタリスク() { + val lexer = Lexer() + + val actual = lexer.lex("*a*") + + println(actual) + + assertContentEquals( + listOf( + Asterisk(1), + Text("a"), + Asterisk(1) + ), actual + ) + } + + @Test + fun アスタリスク2() { + val lexer = Lexer() + + val actual = lexer.lex("> *a*") + + println(actual) + + assertContentEquals( + listOf( + Quote(1), + Asterisk(1), + Text("a"), + Asterisk(1) + ), actual + ) + } } \ No newline at end of file