packages feed

disco-0.2: src/Disco/Syntax/Prims.hs

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveDataTypeable #-}

-----------------------------------------------------------------------------

-----------------------------------------------------------------------------

-- SPDX-License-Identifier: BSD-3-Clause

-- |
-- Module      :  Disco.Syntax.Prims
-- Copyright   :  disco team and contributors
-- Maintainer  :  byorgey@gmail.com
--
-- Concrete syntax for the prims (i.e. built-in constants) supported
-- by the language.
module Disco.Syntax.Prims (
  Prim (..),
  PrimInfo (..),
  primTable,
  toPrim,
  primMap,
) where

import GHC.Generics (Generic)
import Unbound.Generics.LocallyNameless

import Data.Map (Map)
import qualified Data.Map as M

import Data.Data (Data)
import Disco.Syntax.Operators

------------------------------------------------------------
-- Prims
------------------------------------------------------------

-- | Primitives, /i.e./ built-in constants.
data Prim where
  -- | Unary operator
  PrimUOp :: UOp -> Prim
  -- | Binary operator
  PrimBOp :: BOp -> Prim
  -- | Left injection into a sum type.
  PrimLeft :: Prim
  -- | Right injection into a sum type.
  PrimRight :: Prim
  -- | Integer square root (@sqrt@)
  PrimSqrt :: Prim
  -- | Floor of fractional type (@floor@)
  PrimFloor :: Prim
  -- | Ceiling of fractional type (@ceiling@)
  PrimCeil :: Prim
  -- | Absolute value (@abs@)
  PrimAbs :: Prim
  -- | Min
  PrimMin :: Prim
  -- | Max
  PrimMax :: Prim
  -- | Power set (XXX or bag?)
  PrimPower :: Prim
  -- | Container -> list conversion
  PrimList :: Prim
  -- | Container -> bag conversion
  PrimBag :: Prim
  -- | Container -> set conversion
  PrimSet :: Prim
  -- | bag -> set of counts conversion
  PrimB2C :: Prim
  -- | set of counts -> bag conversion
  PrimC2B :: Prim
  -- | unsafe set of counts -> bag conversion
  --   that assumes all distinct
  PrimUC2B :: Prim
  -- | Map k v -> Set (k × v)
  PrimMapToSet :: Prim
  -- | Set (k × v) -> Map k v
  PrimSetToMap :: Prim
  -- | Get Adjacency list of Graph
  PrimSummary :: Prim
  -- | Construct a graph Vertex
  PrimVertex :: Prim
  -- | Empty graph
  PrimEmptyGraph :: Prim
  -- | Overlay two Graphs
  PrimOverlay :: Prim
  -- | Connect Graph to another with directed edges
  PrimConnect :: Prim
  -- | Insert into map
  PrimInsert :: Prim
  -- | Get value associated with key in map
  PrimLookup :: Prim
  -- | Each operation for containers
  PrimEach :: Prim
  -- | Reduce operation for containers
  PrimReduce :: Prim
  -- | Filter operation for containers
  PrimFilter :: Prim
  -- | Monadic join for containers
  PrimJoin :: Prim
  -- | Generic merge operation for bags/sets
  PrimMerge :: Prim
  -- | Efficient primality test
  PrimIsPrime :: Prim
  -- | Factorization
  PrimFactor :: Prim
  -- | Turn a rational into a pair (num, denom)
  PrimFrac :: Prim
  -- | Crash
  PrimCrash :: Prim
  -- | @[x, y, z .. e]@
  PrimUntil :: Prim
  -- | Test whether a proposition holds
  PrimHolds :: Prim
  -- | Lookup OEIS sequence
  PrimLookupSeq :: Prim
  -- | Extend OEIS sequence
  PrimExtendSeq :: Prim
  -- | Generates a pseudorandom number generator
  PrimSeed :: Prim
  -- | Given a range and a generator, generates random number
  PrimRandom :: Prim
  deriving (Show, Read, Eq, Ord, Generic, Alpha, Subst t, Data)

------------------------------------------------------------
-- Concrete syntax for prims
------------------------------------------------------------

-- | An info record for a single primitive name, containing the
--   primitive itself, its concrete syntax, and whether it is
--   "exposed", /i.e./ available to be used in the surface syntax of
--   the basic language.  Unexposed prims can only be referenced by
--   enabling the Primitives language extension and prefixing their
--   name by @$@.
data PrimInfo = PrimInfo
  { thePrim :: Prim
  , primSyntax :: String
  , primExposed :: Bool
  -- Is the prim available in the normal syntax of the language?
  --
  --   primExposed = True means that the bare primSyntax can be used
  --   in the surface syntax, and the prim will be pretty-printed as
  --   the primSyntax.
  --
  --   primExposed = False means that the only way to enter it is to
  --   enable the Primitives language extension and write a $
  --   followed by the primSyntax.  The prim will be pretty-printed with a $
  --   prefix.
  --
  --   In no case is a prim a reserved word.
  }

-- | A table containing a 'PrimInfo' record for every non-operator
--   'Prim' recognized by the language.
primTable :: [PrimInfo]
primTable =
  [ PrimInfo PrimLeft "left" True
  , PrimInfo PrimRight "right" True
  , PrimInfo (PrimUOp Not) "not" True
  , PrimInfo PrimSqrt "sqrt" True
  , PrimInfo PrimFloor "floor" True
  , PrimInfo PrimCeil "ceiling" True
  , PrimInfo PrimAbs "abs" True
  , PrimInfo PrimMin "min" True
  , PrimInfo PrimMax "max" True
  , PrimInfo PrimPower "power" True
  , PrimInfo PrimList "list" True
  , PrimInfo PrimBag "bag" True
  , PrimInfo PrimSet "set" True
  , PrimInfo PrimB2C "bagCounts" True
  , PrimInfo PrimC2B "bagFromCounts" True
  , PrimInfo PrimUC2B "unsafeBagFromCounts" False
  , PrimInfo PrimMapToSet "mapToSet" True
  , PrimInfo PrimSetToMap "map" True
  , PrimInfo PrimSummary "summary" True
  , PrimInfo PrimVertex "vertex" True
  , PrimInfo PrimEmptyGraph "emptyGraph" True
  , PrimInfo PrimOverlay "overlay" True
  , PrimInfo PrimConnect "connect" True
  , PrimInfo PrimInsert "insert" True
  , PrimInfo PrimLookup "lookup" True
  , PrimInfo PrimEach "each" True
  , PrimInfo PrimReduce "reduce" True
  , PrimInfo PrimFilter "filter" True
  , PrimInfo PrimJoin "join" False
  , PrimInfo PrimMerge "merge" False
  , PrimInfo PrimIsPrime "isPrime" False
  , PrimInfo PrimFactor "factor" False
  , PrimInfo PrimFrac "frac" False
  , PrimInfo PrimCrash "crash" False
  , PrimInfo PrimUntil "until" False
  , PrimInfo PrimHolds "holds" True
  , PrimInfo PrimLookupSeq "lookupSequence" False
  , PrimInfo PrimExtendSeq "extendSequence" False
  , PrimInfo PrimSeed "seed" True
  , PrimInfo PrimRandom "random" True
  ]

-- | Find any exposed prims with the given name.
toPrim :: String -> [Prim]
toPrim x = [p | PrimInfo p syn True <- primTable, syn == x]

-- | A convenient map from each 'Prim' to its info record.
primMap :: Map Prim PrimInfo
primMap =
  M.fromList $
    [(p, pinfo) | pinfo@(PrimInfo p _ _) <- primTable]