feat(lexer): Scan dot
This commit is contained in:
parent
f72501fde2
commit
3e80aee0db
6 changed files with 67 additions and 33 deletions
5
src/lexer/Error.kt
Normal file
5
src/lexer/Error.kt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package lexer
|
||||||
|
|
||||||
|
class Error(message: String, position: LexerPosition) : Exception("""
|
||||||
|
Error at ${position.line}:${position.column}: $message
|
||||||
|
""".trimIndent())
|
|
@ -1,11 +1,44 @@
|
||||||
package lexer
|
package lexer
|
||||||
|
|
||||||
class Lexer {
|
import java.util.LinkedList
|
||||||
fun scan(source: String): List<Token> {
|
|
||||||
if (source.isEmpty()) {
|
class Lexer(private val source: String) {
|
||||||
return listOf(Token(TokenType.EOF, LexerPosition(1, 1, 0)))
|
private var tokens: List<Token> = LinkedList()
|
||||||
|
private val position: LexerPosition = LexerPosition(0, 0, 0)
|
||||||
|
private var offset: Int = 0
|
||||||
|
|
||||||
|
fun scan(): List<Token> {
|
||||||
|
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]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
package lexer
|
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
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package lexer
|
package lexer
|
||||||
|
|
||||||
enum class TokenType {
|
enum class TokenType {
|
||||||
|
DOT,
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,35 @@
|
||||||
package be.ugent.logprog.lexer
|
package be.ugent.logprog.lexer
|
||||||
|
|
||||||
|
import lexer.Error
|
||||||
import lexer.Lexer
|
import lexer.Lexer
|
||||||
import lexer.TokenType
|
import lexer.TokenType
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.junit.jupiter.api.assertThrows
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
class LexerScanTest {
|
class LexerScanTest {
|
||||||
@Test
|
@Test
|
||||||
fun scan_emptyString_returnsEOF() {
|
fun scan_emptyString_returnsEOF() {
|
||||||
val lexer = Lexer()
|
val lexer = Lexer("")
|
||||||
val tokens = lexer.scan("")
|
val tokens = lexer.scan()
|
||||||
assertEquals(1, tokens.size)
|
assertEquals(1, tokens.size)
|
||||||
assertEquals(TokenType.EOF, tokens[0].type)
|
assertEquals(TokenType.EOF, tokens[0].type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun scan_unknownSymbol_returnsError() {
|
||||||
|
val lexer = Lexer("€")
|
||||||
|
assertThrows<Error>({
|
||||||
|
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}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Reference in a new issue