packages feed

descript-lang-0.2.0.0: src/Descript/BasicInj/Data/Atom/PropPath.hs

{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE OverloadedStrings #-}

module Descript.BasicInj.Data.Atom.PropPath
  ( PropPath (..)
  , SubPropPath
  , PathElem (..)
  , immPath
  , subPath
  , appendSubpath
  , stripPrefixPath
  ) where

import Descript.BasicInj.Data.Atom.Scope
import Descript.Lex.Data.Atom
import Descript.Misc
import Data.Monoid
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.List.NonEmpty as NonEmpty
import qualified Core.Data.List.NonEmpty as NonEmpty

-- | A property path. Refers to a top-level value's property, or
-- property of a property, or property of a property of a property, etc.
data PropPath an
  = PropPath an (NonEmpty (PathElem an))
  deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)

-- | A part of a property path. It can refer to a top-level value, or
-- a property, or a property of a property, etc.
type SubPropPath an = [PathElem an]

-- | A property path element. Refers to a property key in a type of
-- record. For example, `a<Foo` would refer to `5` in `Foo[a: 5]`.
data PathElem an
  = PathElem
  { pathElemAnn :: an
  , keyRef :: Symbol an -- ^ Refers to the property key (e.g. `a`).
  , headRef :: FSymbol an -- ^ Refers to the type of record (e.g. `Foo`).
  } deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)

instance Ann PropPath where
  getAnn (PropPath ann _) = ann

instance Ann PathElem where
  getAnn = pathElemAnn

instance Printable PropPath where
  aprintRec sub (PropPath _ elems) = pintercal ">" $ map sub $ NonEmpty.toList elems

instance Printable PathElem where
  aprintRec sub (PathElem _ key head') = sub key <> pimp ("<" <> sub head')

instance (Show an) => Summary (PropPath an) where
  summaryRec = pprintSummaryRec

instance (Show an) => Summary (PathElem an) where
  summaryRec = pprintSummaryRec

-- | A 'PropPath' with 1 element.
immPath :: PathElem () -> PropPath ()
immPath x = PropPath () $ x :| []

-- | Prepends the element to the path.
subPath :: PathElem () -> PropPath () -> PropPath ()
subPath x (PropPath () xs) = PropPath () $ x NonEmpty.<| xs

-- | Adds the elements in the subpath to the end of the path.
appendSubpath :: PropPath () -> SubPropPath () -> PropPath ()
appendSubpath (PropPath () (x :| xs)) suf = PropPath () $ x :| xs ++ suf

-- | If the second path starts with the first, returns the part after.
-- Otherwise returns 'Nothing'.
stripPrefixPath :: PropPath () -> PropPath () -> Maybe (SubPropPath ())
PropPath _ xs `stripPrefixPath` PropPath _ ys
  = xs `NonEmpty.stripPrefix` ys