Skip to content

Commit

Permalink
refactor: Replace ANTLR version parser with a recursive decent parser #…
Browse files Browse the repository at this point in the history
  • Loading branch information
rholshausen committed Oct 26, 2022
1 parent c77ddf2 commit 47e8c9e
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 109 deletions.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package au.com.dius.pact.core.support

import com.github.michaelbull.result.Err
import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.Result

data class Version(
var major: Int,
var minor: Int,
var patch: Int? = null
) {
override fun toString(): String {
return if (patch == null) {
"$major.$minor"
} else {
"$major.$minor.$patch"
}
}

companion object {
val INT = Regex("^\\d+")

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

val major = when (val result = parseInt(buffer, index)) {
is Ok -> {
buffer = result.value.second
index = result.value.third
result.value.first
}
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 minor = when (val result = parseInt(buffer, index)) {
is Ok -> {
buffer = result.value.second
index = result.value.third
result.value.first
}
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))
is Err -> result
}
}
buffer.isEmpty() -> Ok(Version(major, minor))
else -> Err("Unexpected character '${buffer[0]}' at index $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 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))
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package au.com.dius.pact.core.support

import spock.lang.Specification
import org.antlr.v4.runtime.InputMismatchException
import spock.lang.Unroll

class VersionParserSpec extends Specification {

Expand All @@ -17,6 +18,25 @@ class VersionParserSpec extends Specification {

def 'parse invalid version'() {
expect:
Version.parse('lkzasdjskjdf').component2() instanceof InputMismatchException
Version.parse('lkzasdjskjdf').component2() == 'Was expecting an integer at index 0'
}

@Unroll
def 'parse errors'() {
expect:
Version.parse(version).component2() == error

where:

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'
'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.10.sss' | 'Was expecting an integer at index 7'
}
}

0 comments on commit 47e8c9e

Please sign in to comment.