All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fs2.data.esp.Pattern.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2024 fs2-data Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package fs2.data
package esp

import pattern._

import cats.data.NonEmptyChain
import cats.syntax.all._

/** A pattern to be matched.
  * A pattern can capture a submatch, that is then usable in the RHS.
  */
sealed trait Pattern[Guard, T] {
  def |(that: Pattern[Guard, T]): Pattern[Guard, T] =
    (this, that) match {
      case (Pattern.Wildcard(), _) | (_, Pattern.Wildcard()) => Pattern.Wildcard()
      case (Pattern.Or(alts1), Pattern.Or(alts2))            => Pattern.Or(alts1 ++ alts2)
      case (_, _)                                            => Pattern.Or(NonEmptyChain(this, that))
    }

  def when(guard: Guard): Pattern[Guard, T] =
    Pattern.Guarded(this, guard)
}

object Pattern {

  /** Matches anything. */
  case class Wildcard[Guard, T]() extends Pattern[Guard, T]

  /** Matches the end of stream. */
  case class EOS[Guard, T]() extends Pattern[Guard, T]

  /** Matches the input in a state at a depth for some input pattern. */
  case class Input[Guard, T](q: Option[Int], d: Option[Int], inner: Pattern[Guard, T]) extends Pattern[Guard, T]

  /** Matches some open tag. */
  case class Open[Guard, T](tag: Option[T]) extends Pattern[Guard, T]

  /** Matches some close tag. */
  case class Close[Guard, T](tag: Option[T]) extends Pattern[Guard, T]

  /** Matches some leaf value. */
  case class Leaf[Guard, T](value: Option[T]) extends Pattern[Guard, T]

  /** Alternative, matched from left to right. */
  case class Or[Guard, T](patterns: NonEmptyChain[Pattern[Guard, T]]) extends Pattern[Guard, T]

  /** A guarded pattern. */
  case class Guarded[Guard, T](inner: Pattern[Guard, T], guard: Guard) extends Pattern[Guard, T]

  implicit def PatternIsPattern[G, T]: IsPattern[Pattern[G, T], G, Tag[T]] =
    new IsPattern[Pattern[G, T], G, Tag[T]] {

      override val trueTag: Tag[T] = Tag.Open

      override def decompose(pat: Pattern[G, T]): List[RawSkeleton[G, Tag[T]]] =
        decompose(pat, None)

      private def decompose(pat: Pattern[G, T], guard: Option[G]): List[RawSkeleton[G, Tag[T]]] =
        pat match {
          case Wildcard() =>
            List(RawSkeleton.Wildcard[G, Tag[T]](guard))
          case EOS() =>
            List(RawSkeleton.Constructor[G, Tag[T]](Tag.End, Nil, guard))
          case Input(Some(q), Some(d), inner) =>
            decompose(inner).map { inner =>
              RawSkeleton.Constructor[G, Tag[T]](
                Tag.Input,
                List(RawSkeleton.noArgConstructor(Tag.State(q)), RawSkeleton.noArgConstructor(Tag.Depth(d)), inner),
                guard)
            }
          case Input(Some(q), None, inner) =>
            decompose(inner).map { inner =>
              RawSkeleton.Constructor[G, Tag[T]](
                Tag.Input,
                List(RawSkeleton.noArgConstructor(Tag.State(q)), RawSkeleton.Wildcard(none), inner),
                guard)
            }
          case Input(None, Some(d), inner) =>
            decompose(inner).map { inner =>
              RawSkeleton.Constructor[G, Tag[T]](
                Tag.Input,
                List(RawSkeleton.wildcard, RawSkeleton.noArgConstructor(Tag.Depth(d)), inner),
                guard)
            }
          case Input(None, None, inner) =>
            decompose(inner).map { inner =>
              RawSkeleton
                .Constructor[G, Tag[T]](Tag.Input, List(RawSkeleton.wildcard, RawSkeleton.wildcard, inner), guard)
            }
          case Open(None) =>
            List(RawSkeleton.Constructor[G, Tag[T]](Tag.Open, List(RawSkeleton.wildcard), guard))
          case Open(Some(tag)) =>
            List(
              RawSkeleton
                .Constructor[G, Tag[T]](Tag.Open, List(RawSkeleton.noArgConstructor(Tag.Name(tag))), guard))
          case Close(None) =>
            List(RawSkeleton.Constructor[G, Tag[T]](Tag.Close, List(RawSkeleton.wildcard), guard))
          case Close(Some(tag)) =>
            List(
              RawSkeleton
                .Constructor[G, Tag[T]](Tag.Close, List(RawSkeleton.noArgConstructor(Tag.Name(tag))), guard))
          case Leaf(None) =>
            List(RawSkeleton.Constructor[G, Tag[T]](Tag.Leaf, List(RawSkeleton.wildcard), guard))
          case Leaf(Some(v)) =>
            List(
              RawSkeleton
                .Constructor[G, Tag[T]](Tag.Leaf, List(RawSkeleton.noArgConstructor(Tag.Value(v))), guard))
          case Or(alts) =>
            alts.foldMap(decompose(_, guard))
          case Guarded(p, g) =>
            decompose(p, Some(g))
        }

    }

}

class PatternDsl[Guard, T] {

  def state(q: Int)(inner: Pattern[Guard, T]): Pattern[Guard, T] =
    Pattern.Input(q.some, none, inner)

  def state(q: Int, d: Int)(inner: Pattern[Guard, T]): Pattern[Guard, T] =
    Pattern.Input(q.some, d.some, inner)

  def value(v: T): Pattern[Guard, T] =
    Pattern.Leaf(v.some)

  val value: Pattern[Guard, T] =
    Pattern.Leaf(none)

  val eos: Pattern[Guard, T] =
    Pattern.EOS()

  val any: Pattern[Guard, T] =
    Pattern.Wildcard()

  def open(t: T): Pattern[Guard, T] =
    Pattern.Open(t.some)

  val open: Pattern[Guard, T] =
    Pattern.Open(none)

  def close(t: T): Pattern[Guard, T] =
    Pattern.Close(t.some)

  val close: Pattern[Guard, T] =
    Pattern.Close(none)

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy