1
1
package io.github.cybercodernaj.parkour.lexer
2
2
3
- import arrow.core.None
4
- import arrow.core.Option
3
+ import arrow.core.*
5
4
import arrow.core.raise.OptionRaise
6
5
import arrow.core.raise.option
7
6
import io.github.cybercodernaj.parkour.datasource.TextSource
@@ -72,9 +71,16 @@ class Lexer(
72
71
73
72
private var insideMultilineComment = false
74
73
75
- private val _hardKeywords = hardKeywords.sortedByDescending(String ::length)
76
- private val _separators = separators.sortedByDescending(String ::length)
77
- private val _operators = operators.sortedByDescending(String ::length)
74
+ private val trieMap = StringTrieMap <Kind >()
75
+ private enum class Kind {
76
+ KEYWORD , OPERATOR , SEPARATOR
77
+ }
78
+
79
+ init {
80
+ hardKeywords.forEach {
81
+ trieMap[it] = Kind .KEYWORD
82
+ }
83
+ }
78
84
79
85
/* *
80
86
* Fetches the next [Token] from the source
@@ -83,39 +89,25 @@ class Lexer(
83
89
* @since 0.1.0
84
90
*/
85
91
internal fun nextToken (): Token {
92
+ currentLine.onNone { fetchLine() }
93
+
86
94
currentLine.fold(
87
- ifEmpty = { fetchLine() },
95
+ ifEmpty = { return Token . EOF },
88
96
ifSome = {
89
- if (position.col >= it.length) {
90
- position = position.nextLine() // This will implicitly call fetchCurrentLine() on the new line
97
+ if (it.isBlank()) {
98
+ position = position.nextLine()
99
+ return nextToken()
91
100
}
92
101
}
93
102
)
94
103
95
- return fetchToken()
96
- }
97
-
98
- private fun fetchToken (): Token {
99
- if (currentLine.isNone())
100
- return Token .EOF
101
-
102
- if (currentLine.isSome { it.isBlank() }) {
103
- position = position.nextLine()
104
- return nextToken()
105
- }
106
-
107
104
fastForwardToContent()
108
105
109
- val contenders = listOf (identifiers())
106
+ val winner = listOf (identifiers())
110
107
.mapNotNull { it.getOrNull() }
111
-
112
- return if (contenders.isEmpty())
113
- return nextToken()
114
- else {
115
- val winner = contenders.maxBy { it.end - it.start }
116
- position = position.copy(col = winner.end.col + 1 )
117
- winner
118
- }
108
+ .getWinnerOrNullOrThrow() ? : nextToken()
109
+ position = position.copy(col = winner.end.col + 1 )
110
+ return winner
119
111
}
120
112
121
113
/* *
@@ -160,6 +152,41 @@ private fun <A> Option<A>.getOrThrow(cause: () -> Exception): A {
160
152
return getOrNull() ? : throw cause()
161
153
}
162
154
155
+ private fun List<Token>.getWinnerOrNullOrThrow (): Token ? {
156
+ if (this .isEmpty())
157
+ return null
158
+
159
+ var maxSize = 0
160
+ val winners = mutableSetOf<Token >()
161
+ for (token in this ) {
162
+ if (token.size > maxSize) {
163
+ winners.clear()
164
+ winners.add(token)
165
+ maxSize = token.size
166
+ } else if (token.size == maxSize) {
167
+ winners.add(token)
168
+ }
169
+ }
170
+
171
+ when (winners.size) {
172
+ 1 -> return winners.first()
173
+ 2 -> {
174
+ val keywordIdentifier = winners.separateEither {
175
+ when (it) {
176
+ is Token .Keyword -> it.left()
177
+ is Token .Identifier -> it.right()
178
+ else -> throw LexicalException (" Ambiguity error" )
179
+ }
180
+ }
181
+ // first is the lefts containing keyword.
182
+ // keywords triumph over identifiers.
183
+ return keywordIdentifier.first[0 ]
184
+ }
185
+
186
+ else -> throw LexicalException (" Ambiguity error" )
187
+ }
188
+ }
189
+
163
190
// private fun updateTokenStream() {
164
191
// fetchNextLine()
165
192
// tokenIndex = 0 // reset the counter
0 commit comments