Last active
February 5, 2021 09:13
-
-
Save ygrenzinger/8ded51b3fa5dd7f03dccaf2b7836dbc5 to your computer and use it in GitHub Desktop.
Kata Becom Tech 2021-02-03
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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")) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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")) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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