diff --git a/src/lexer/Error.kt b/src/lexer/Error.kt new file mode 100644 index 0000000..f31c686 --- /dev/null +++ b/src/lexer/Error.kt @@ -0,0 +1,5 @@ +package lexer + +class Error(message: String, position: LexerPosition) : Exception(""" + Error at ${position.line}:${position.column}: $message +""".trimIndent()) \ No newline at end of file diff --git a/src/lexer/Lexer.kt b/src/lexer/Lexer.kt index 93a9d5c..173a8a2 100644 --- a/src/lexer/Lexer.kt +++ b/src/lexer/Lexer.kt @@ -1,11 +1,44 @@ package lexer -class Lexer { - fun scan(source: String): List { - if (source.isEmpty()) { - return listOf(Token(TokenType.EOF, LexerPosition(1, 1, 0))) +import java.util.LinkedList + +class Lexer(private val source: String) { + private var tokens: List = LinkedList() + private val position: LexerPosition = LexerPosition(0, 0, 0) + private var offset: Int = 0 + + fun scan(): List { + while (hasNext()) { + val token = scanToken() + tokens += token } - return emptyList() + tokens += Token(TokenType.EOF, position) + + return tokens + } + + private fun scanToken(): Token { + val c = peek() + val token = when (c) { + '.' -> Token(TokenType.DOT, position) + else -> throw Error("Unknown symbol: $c", position) + } + + offset++ + position.column++ + return token + } + + private fun hasNext(): Boolean { + return offset < source.length + } + + private fun peek(): Char { + if (!hasNext()) { + throw Error("Unexpected end of input", position) + } + + return source[offset] } } diff --git a/src/lexer/LexerPosition.kt b/src/lexer/LexerPosition.kt index 2ca10bc..4c39451 100644 --- a/src/lexer/LexerPosition.kt +++ b/src/lexer/LexerPosition.kt @@ -1,5 +1,5 @@ package lexer -class LexerPosition(val line: Int, val column: Int, val length: Int) { +class LexerPosition(val line: Int, var column: Int, val length: Int) { // Do nothing } diff --git a/src/lexer/TokenType.kt b/src/lexer/TokenType.kt index bace57e..1863986 100644 --- a/src/lexer/TokenType.kt +++ b/src/lexer/TokenType.kt @@ -1,5 +1,7 @@ package lexer enum class TokenType { + DOT, + EOF } diff --git a/tests/lexer/LexerScanTest.kt b/tests/lexer/LexerScanTest.kt index d2ff248..68aa9e3 100644 --- a/tests/lexer/LexerScanTest.kt +++ b/tests/lexer/LexerScanTest.kt @@ -1,16 +1,35 @@ package be.ugent.logprog.lexer +import lexer.Error import lexer.Lexer import lexer.TokenType import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows import kotlin.test.assertEquals class LexerScanTest { @Test fun scan_emptyString_returnsEOF() { - val lexer = Lexer() - val tokens = lexer.scan("") + val lexer = Lexer("") + val tokens = lexer.scan() assertEquals(1, tokens.size) assertEquals(TokenType.EOF, tokens[0].type) } + + @Test + fun scan_unknownSymbol_returnsError() { + val lexer = Lexer("€") + assertThrows({ + val tokens = lexer.scan() + }) + } + + @Test + fun scan_dot_returnsDot() { + val lexer = Lexer(".") + val tokens = lexer.scan() + assertEquals(2, tokens.size) + assertEquals(TokenType.DOT, tokens[0].type, "Expected DOT token, got ${tokens[0].type}") + assertEquals(TokenType.EOF, tokens[1].type, "Expected EOF token, got ${tokens[1].type}") + } } diff --git a/tests/someTest.kt b/tests/someTest.kt deleted file mode 100644 index fdcd6e6..0000000 --- a/tests/someTest.kt +++ /dev/null @@ -1,25 +0,0 @@ -package be.ugent.logprog - -import org.junit.jupiter.api.Test - -import org.junit.jupiter.api.Assertions.* -import testMe - -class MainTest { - @Test - fun Main_should_return_string() { - assertTrue(true) - } - - @Test - fun testMe_should_return_string() { - assertEquals("Hello, Kotlin Command Line Utility!", testMe()) - assertInstanceOf(String::class.java, testMe()) - } - - @Test - fun testMe_shouldfail() { - assertTrue(false, "This test should fail"); - } -} -