Skip to content

Instantly share code, notes, and snippets.

@ygrenzinger
Last active February 5, 2021 09:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ygrenzinger/8ded51b3fa5dd7f03dccaf2b7836dbc5 to your computer and use it in GitHub Desktop.
Save ygrenzinger/8ded51b3fa5dd7f03dccaf2b7836dbc5 to your computer and use it in GitHub Desktop.
Kata Becom Tech 2021-02-03
import scala.util.matching.Regex
trait Element
case class Number(value: Int) extends Element
object PlusOperator extends Element
case class ParseResult(elements: List[Element], rest: String)
trait Parser {
def parse(value: String): Option[ParseResult]
}
case class AndCombinator(parsers: List[Parser]) extends Parser {
def parse(value: String): Option[ParseResult] = {
var r: Option[ParseResult] = None
var current = value
var elements = List[Element]()
parsers.foreach { parser =>
parser.parse(current) match {
case None => return None
case Some(ParseResult(elts, rest)) =>
current = rest
elements = elements ++ elts
}
}
Some(ParseResult(elements, ""))
}
}
object NumberParser extends Parser {
def parse(value: String): Option[ParseResult] = {
val regex = "^(\\d+)(.*)".r
if (regex.matches(value)) {
val result = regex.findAllIn(value)
val s = result.group(1)
Some(ParseResult(List(Number(s.toInt)), result.group(2)))
} else {
None
}
}
}
object PlusOperatorParser extends Parser {
def parse(value: String): Option[ParseResult] = {
val regex = "^\\+(.*)".r
if (regex.matches(value)) {
val result = regex.findAllIn(value)
Some(ParseResult(List(PlusOperator), result.group(1)))
} else {
None
}
}
}
import org.junit.Test
import org.junit.Assert._
class ParserTest {
@Test def should_parse_expression(): Unit = {
assertEquals(
Some(ParseResult(List(Number(3), PlusOperator, Number(2)), "")),
AndCombinator(List(NumberParser, PlusOperatorParser, NumberParser)).parse("3+2"))
}
@Test def should_parse_operator(): Unit = {
assertEquals(
Some(ParseResult(List(PlusOperator), "2")),
PlusOperatorParser.parse("+2"))
}
@Test def should_parse_number(): Unit = {
assertEquals(
Some(ParseResult(List(Number(3)), "+2")),
NumberParser.parse("3+2"))
}
@Test def should_fail_to_parse_number(): Unit = {
assertEquals(
None,
NumberParser.parse("+2"))
}
}
import org.junit.Test
import org.junit.Assert._
import ParseResult._
class ParserTest {
@Test def should_parse_expression(): Unit = {
assertEquals(
Success(List(Number(3), Operator.Plus, Number(2)), ""),
AndCombinator(List(NumberParser, PlusOperatorParser, NumberParser)).parse("3+2"))
}
@Test def should_parse_operator(): Unit = {
assertEquals(
Success(List(Operator.Plus), "2"),
PlusOperatorParser.parse("+2"))
}
@Test def should_parse_number(): Unit = {
assertEquals(
Success(List(Number(3)), "+2"),
NumberParser.parse("3+2"))
}
@Test def should_fail_to_parse_number(): Unit = {
assertEquals(
Failure("+2"),
NumberParser.parse("+2"))
}
}
import scala.annotation.tailrec
import scala.util.matching.Regex
sealed trait Element
case class Number(value: Int) extends Element
enum Operator extends Element {
case Plus
}
enum ParseResult {
case Success(elements: List[Element], rest: String)
case Failure(rest: String)
}
import ParseResult._
trait Parser {
def parse(value: String): ParseResult
}
case class AndCombinator(parsers: List[Parser]) extends Parser {
@tailrec
private def parse(parsers: List[Parser], elements: List[Element], rest: String): ParseResult = {
if (parsers.isEmpty) {
Success(elements, rest)
} else {
parsers.head.parse(rest) match {
case Success(elmts, r) => parse(parsers.tail, elements ++ elmts, r)
case failure => failure
}
}
}
def parse(value: String): ParseResult = {
parse(parsers,List(), value)
}
}
object NumberParser extends Parser {
def parse(value: String): ParseResult = {
val regex = "^(\\d+)(.*)".r
if (regex.matches(value)) {
val result = regex.findAllIn(value)
val s = result.group(1)
Success(List(Number(s.toInt)), result.group(2))
} else {
Failure(value)
}
}
}
object PlusOperatorParser extends Parser {
def parse(value: String): ParseResult = {
val regex = "^\\+(.*)".r
if (regex.matches(value)) {
val result = regex.findAllIn(value)
Success(List(Operator.Plus), result.group(1))
} else {
Failure(value)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment