Skip to content

Commit

Permalink
refactor: extract common lexer functions from version parser #1615
Browse files Browse the repository at this point in the history
  • Loading branch information
rholshausen committed Oct 27, 2022
1 parent 0b1be93 commit 739a40d
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package au.com.dius.pact.core.support

import au.com.dius.pact.core.support.parsers.StringLexer
import com.github.michaelbull.result.Err
import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.Result
Expand All @@ -22,68 +23,52 @@ data class Version(

@JvmStatic
fun parse(version: String): Result<Version, String> {
var buffer = version
var index = 0
val lexer = StringLexer(version)

val major = when (val result = parseInt(buffer, index)) {
is Ok -> {
buffer = result.value.second
index = result.value.third
result.value.first
}
val major = when (val result = parseInt(lexer)) {
is Ok -> result.value
is Err -> return result
}

when (val dot = parseChar('.', buffer, index)) {
is Ok -> {
buffer = dot.value.first
index = dot.value.second
}
is Err -> {
return dot
}
val err = parseChar('.', lexer)
if (err != null) {
return Err(err)
}

val minor = when (val result = parseInt(buffer, index)) {
is Ok -> {
buffer = result.value.second
index = result.value.third
result.value.first
}
val minor = when (val result = parseInt(lexer)) {
is Ok -> result.value
is Err -> return result
}

val dot = parseChar('.', buffer, index)
return when {
dot is Ok -> {
buffer = dot.value.first
index = dot.value.second
when (val result = parseInt(buffer, index)) {
is Ok -> Ok(Version(major, minor, result.value.first))
lexer.peekNextChar() == '.' -> {
lexer.advance()
when (val result = parseInt(lexer)) {
is Ok -> if (lexer.empty) {
Ok(Version(major, minor, result.value))
} else {
Err("Unexpected characters '${lexer.remainder}' at index ${lexer.index}")
}
is Err -> result
}
}
buffer.isEmpty() -> Ok(Version(major, minor))
else -> Err("Unexpected character '${buffer[0]}' at index $index")
lexer.empty -> Ok(Version(major, minor))
else -> Err("Unexpected characters '${lexer.remainder}' at index ${lexer.index}")
}
}

private fun parseChar(c: Char, buffer: String, index: Int): Result<Pair<String, Int>, String> {
return when {
buffer.isNotEmpty() && buffer[0] == c -> {
Ok(buffer.substring(1) to (index + 1))
}
else -> Err("Was expecting a $c at index $index")
private fun parseChar(c: Char, lexer: StringLexer): String? {
return when (val ch = lexer.nextChar()) {
null -> "Was expecting a '$c' at index ${lexer.index} but got the end of the input"
c -> null
else -> "Was expecting a '$c' at index ${lexer.index - 1} but got '$ch'"
}
}

private fun parseInt(buffer: String, index: Int): Result<Triple<Int, String, Int>, String> {
return when (val result = INT.find(buffer)) {
null -> Err("Was expecting an integer at index $index")
else -> {
val i = result.value.toInt()
Ok(Triple(i, buffer.substring(result.value.length), index + result.value.length))
}
private fun parseInt(lexer: StringLexer): Result<Int, String> {
return when (val result = lexer.matchRegex(INT)) {
null -> Err("Was expecting an integer at index ${lexer.index}")
else -> Ok(result.toInt())
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package au.com.dius.pact.core.support.parsers

class StringLexer(private val buffer: String) {
var index = 0
private set

val empty: Boolean
get() = index >= buffer.length

val remainder: String
get() = buffer.substring(index)

fun nextChar(): Char? {
val c = peekNextChar()
if (c != null) {
index++
}
return c
}

fun peekNextChar(): Char? {
return if (empty) {
null
} else {
buffer[index]
}
}

fun advance() {
advance(1)
}

fun advance(count: Int) {
for (i in 0 until count) {
index++
}
}

fun skipWhitespace() {
var next = peekNextChar()
while (next != null && Character.isWhitespace(next)) {
advance()
next = peekNextChar()
}
}

fun matchRegex(regex: Regex): String? {
return when (val result = regex.find(buffer.substring(index))) {
null -> null
else -> {
index += result.value.length
result.value
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ class VersionParserSpec extends Specification {
version | error
'' | 'Was expecting an integer at index 0'
'sdsd' | 'Was expecting an integer at index 0'
'0' | 'Was expecting a . at index 1'
'0sass' | 'Was expecting a . at index 1'
'100' | 'Was expecting a . at index 3'
'0' | "Was expecting a '.' at index 1 but got the end of the input"
'0sass' | "Was expecting a '.' at index 1 but got 's'"
'100' | "Was expecting a '.' at index 3 but got the end of the input"
'100.' | 'Was expecting an integer at index 4'
'100.10.' | 'Was expecting an integer at index 7'
'100.10x' | "Unexpected character 'x' at index 6"
'100.10x' | "Unexpected characters 'x' at index 6"
'100.10.sss' | 'Was expecting an integer at index 7'
'100.10.1ss' | "Unexpected characters 'ss' at index 8"
}
}

0 comments on commit 739a40d

Please sign in to comment.