Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package java2scala.homeworks
- import java2scala.homeworks.CharAutomata.{And, Const, Or}
- trait CharAutomata[+A] {
- /** потребить один символ и перейти в следующее состояние */
- def consume(char: Char): CharAutomata[A]
- /** получить текущий результат, если это конец строки */
- def result: Either[String, A]
- /** потребить строку символ за символом */
- def apply(source: String): Either[String, A] = consume(source.head) match {
- case e: Error => e.result
- case c: Const[A] => c.result
- case a: CharAutomata[_] if source.tail.nonEmpty => a(source.tail)
- case a: CharAutomata[_] => a.result
- }
- /** создать автомат, который запустит оба автомата
- * и если первый вернёт ошибку, вернёт результат второго
- */
- def or[B](auto: CharAutomata[B]): CharAutomata[Either[A, B]] = new Or(this, auto)
- /** создать автомат, который запустит оба автомата
- * вернёт результаты обоих, если оба вернут успешный результат
- * и вернёт ошибку, если вернёт ошибку хотя бы один
- */
- def and[B](auto: CharAutomata[B]): CharAutomata[(A, B)] = new And(this, auto)
- }
- object CharAutomata {
- /** создаёт автомат, всегда результирующий с ошибкой
- * с заданным текстом message
- */
- def error(message: String): CharAutomata[Nothing] = new Error(message)
- /** создаёт автомат, всегда успешно результирующий
- * с заданным значением `value`
- */
- def const[A](value: A): CharAutomata[A] = new Const[A](value)
- /** создаёт автомат, возвращающий
- * первое вхождение строчки `substring`
- * или ошибкой
- */
- def find(substring: String): CharAutomata[Int] = new Find(substring)
- /** создаёт автомат, определяющий является ли строчка,
- * если исключить из неё все символы, кроме `'('` и `')'`
- * корректной скобочной последовательностью */
- def balance: CharAutomata[Unit] = new ParenBalance
- /** создаёт автомат, ищущий первое число, из цифр подряд
- * и возвращающий результат в качестве BigInt либо 0
- */
- def parseInt: CharAutomata[BigInt] = new ParseInteger
- /** класс для реализации метода `error` */
- class Error(string: String) extends CharAutomata[Nothing] {
- def consume(char: Char): CharAutomata[Nothing] = this
- def result: Either[String, Nothing] = Left(string)
- }
- /** класс для реализации метода `const` */
- class Const[A] private[CharAutomata] (value: A) extends CharAutomata[A] {
- def consume(char: Char): CharAutomata[A] = this
- def result: Either[String, A] = Right(value)
- }
- /** класс для реализации метода `find` */
- class Find private[CharAutomata] (substring: String, nextSubstrIndex: Int, readChars: Int) extends CharAutomata[Int] {
- def this(substring: String) = this(substring, 0, 0)
- def consume(char: Char): CharAutomata[Int] = {
- if (substring.isEmpty)
- const(0)
- else if (char == substring(nextSubstrIndex)) {
- if (nextSubstrIndex == substring.length - 1)
- const(readChars + 1 - substring.length)
- else
- new Find(substring, nextSubstrIndex + 1, readChars + 1)
- } else
- new Find(substring, 0, readChars + 1)
- }
- def result: Either[String, Int] =
- if (nextSubstrIndex == substring.length)
- Right(readChars - nextSubstrIndex)
- else
- Left(s"Failed to find substring $substring in input sequence")
- }
- /** класс для реализации метода `balance` */
- class ParenBalance private[CharAutomata] (openedStack: Int) extends CharAutomata[Unit] {
- def this() = this(0)
- def consume(char: Char): CharAutomata[Unit] = char match {
- case '(' => new ParenBalance(openedStack + 1)
- case ')' if openedStack > 0 => new ParenBalance(openedStack - 1)
- case ')' => error("Closing bracket on zero balance occured")
- case _ => this
- }
- def result: Either[String, Unit] =
- if (openedStack == 0)
- Right(())
- else
- Left(s"Brackets are not balanced in input sequence. Stopped on balance = $openedStack")
- }
- /** класс для реализации метода `parseInt` */
- class ParseInteger private[CharAutomata] (accum: BigInt) extends CharAutomata[BigInt] {
- def this() = this(0)
- def consume(char: Char): CharAutomata[BigInt] = {
- if (char.isDigit)
- new ParseInteger(accum * 10 + char.asDigit)
- else if (accum != 0)
- const[BigInt](accum)
- else
- this
- }
- def result: Either[String, BigInt] = Right(accum)
- }
- /** класс для реализации метода `and` */
- class And[A, B] private[CharAutomata] (autoA: CharAutomata[A], autoB: CharAutomata[B]) extends CharAutomata[(A, B)] {
- def consume(char: Char): CharAutomata[(A, B)] = new And(autoA.consume(char), autoB.consume(char))
- def result: Either[String, (A, B)] = (autoA.result, autoB.result) match {
- case (Right(a), Right(b)) => Right(a, b)
- case (Left(a), _) => Left(a)
- case (_, Left(b)) => Left(b)
- }
- }
- /** класс для реализации метода `or` */
- class Or[A, B] private[CharAutomata] (autoA: CharAutomata[A], autoB: CharAutomata[B]) extends CharAutomata[Either[A, B]] {
- def consume(char: Char): CharAutomata[Either[A, B]] = new Or(autoA.consume(char), autoB.consume(char))
- def result: Either[String, Either[A, B]] = (autoA.result, autoB.result) match {
- case (Right(a), _) => Right(Left(a))
- case (Left(_), Right(b)) => Right(Right(b))
- case (Left(a), Left(b)) => Left(s"Both automatas failed. 'A': '$a', 'B': '$b'")
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement