glean-0.2.0.0: glean/angle/Glean/Angle/Types.hs
{-
Copyright (c) Meta Platforms, Inc. and affiliates.
All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree.
-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# OPTIONS_GHC -Wno-orphans -Wno-star-is-type #-}
-- | Types representing a source-level schema
module Glean.Angle.Types
( -- * Names and references
Name
, FieldName
, Version
, PredicateRef(..)
, TypeRef(..)
, PredicateId(..)
, tempPredicateId
, TypeId(..)
-- * Source locations
, IsSrcSpan(..)
, SrcSpan(..)
, SrcLoc(..)
, rmLocSchemas
, rmLocSchema
, rmLocEvolves
, rmLocDecl
, rmLocQuery
, rmLocStatement
, rmLocPat
, rmLocField
, rmLocTypeDef
, rmLocType
, rmLocPredDef
, rmTypeLocPredDef
-- * Types
, Type_(..)
, RecordOrSum(..)
-- * Queries
, SourceQuery_(..)
, Ordered(..)
, SourceStatement_(..)
, SourcePat_(..)
, PrimOp(..)
, SeekSection(..)
-- * Schemas and definitions
, DerivingDef_(..)
, TypeDef_(..)
, FieldDef_(..)
, PredicateDef_(..)
, Statement_
, Query_
, Type
, FieldDef
, TypeDef
, Field(..)
, IsWild(..)
, tupleField
, sourcePatSpan
, spanBetween
, PredicateDef
, DerivingInfo(..)
, DeriveWhen(..)
, SourceSchema
, SourceSchemas
, SourceEvolves
, SourceDecl
, SourceRef(..)
, SourceType
, SourceFieldDef
, SourceTypeDef
, SourcePredicateDef
, SourceDerivingInfo
, SourcePat
, SourceStatement
, SourceQuery
, SourcePat'
, SourceStatement'
, SourceQuery'
, SourceDerivingInfo'
, DerivingDef'
, SourceType'
, Type'
, FieldDef'
, PredicateDef'
, SourceSchemas_(..)
, SourceEvolves_(..)
, SourceSchema_(..)
, SourceDecl_(..)
-- * Versions of the Angle syntax
, AngleVersion(..)
, latestAngleVersion
, latestSupportedAngleVersion
-- * Pretty printing
, displayStatement
-- * Description
, Describe(..)
) where
import qualified Data.Aeson as Aeson
import Data.Binary
import Data.ByteString (ByteString)
import qualified Data.ByteString.Lazy as BL
import Data.Hashable
import Data.List
import Data.List.NonEmpty (NonEmpty, toList)
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Text (Text)
import qualified Data.Text.Encoding as Text
import Compat.Prettyprinter
import Data.Bifunctor
import Data.Bifoldable
import GHC.Generics
import Glean.Angle.Hash
import Glean.Display
import Glean.Types (PredicateRef(..), TypeRef(..), Version)
-- -----------------------------------------------------------------------------
-- Names and references
type Name = Text
type FieldName = Text
-- | A reference to a name or type in a source schema. Versions are
-- often omitted at this level, and will be later resolved by
-- resolveSchema.
data SourceRef = SourceRef
{ sourceRefName :: Name
, sourceRefVersion :: Maybe Version
}
deriving (Show, Eq, Ord, Generic, Hashable)
instance Binary SourceRef
-- -----------------------------------------------------------------------------
-- Source locations
-- | A 'SrcSpan' delimits a portion of a text file.
-- The end position is the column /after/ the end of the span.
-- That is, a span of (1,1)-(1,2) is one character long, and a span of
-- (1,1)-(1,1) is zero characters long.
data SrcSpan = SrcSpan
{ spanStart :: {-# UNPACK #-} !SrcLoc -- inclusive
, spanEnd :: {-# UNPACK #-} !SrcLoc -- exclusive
}
deriving (Eq, Show)
-- | A point in a source text file.
data SrcLoc = SrcLoc
{ locLine :: {-# UNPACK #-} !Int
, locCol :: {-# UNPACK #-} !Int
}
deriving (Show, Eq)
-- -----------------------------------------------------------------------------
-- Queries
data SourceQuery_ s st p t = SourceQuery
{ srcQueryHead :: Maybe (SourcePat_ s st p t)
, srcQueryStmts :: [SourceStatement_ s st p t]
, srcQueryOrdered :: Ordered
}
deriving (Eq, Show, Generic, Functor)
data Ordered = Ordered | Unordered
deriving (Eq, Show, Generic)
instance Binary Ordered
instance (Binary p, Binary t) => Binary (SourceQuery_ () () p t)
instance Bifunctor (SourceQuery_ s st) where
bimap f g (SourceQuery h s o) =
SourceQuery (fmap (bimap f g) h) (fmap (bimap f g) s) o
instance Bifoldable (SourceQuery_ s st ) where
bifoldMap f g (SourceQuery h s _) =
foldMap (bifoldMap f g) h <> foldMap (bifoldMap f g) s
data SourceStatement_ s st p t =
SourceStatement (SourcePat_ s st p t) (SourcePat_ s st p t)
deriving (Eq, Show, Generic, Functor)
instance (Binary p, Binary t) => Binary (SourceStatement_ () () p t)
instance Bifunctor (SourceStatement_ s st) where
bimap f g (SourceStatement l r) = SourceStatement (bimap f g l) (bimap f g r)
instance Bifoldable (SourceStatement_ s st) where
bifoldMap f g (SourceStatement l r) = bifoldMap f g l <> bifoldMap f g r
data SourcePat_ s st p t
= Nat s Word64
| String s Text
| StringPrefix s Text
| ByteArray s ByteString
-- ^ There's no concrete syntax for this (yet), but it can be used
-- via the DSL.
| Array s [SourcePat_ s st p t]
| ArrayPrefix s (NonEmpty (SourcePat_ s st p t))
| Tuple s [SourcePat_ s st p t]
| Struct s [Field s st p t]
| App s (SourcePat_ s st p t) [SourcePat_ s st p t]
| KeyValue s (SourcePat_ s st p t) (SourcePat_ s st p t)
| Elements s (SourcePat_ s st p t)
| All s (SourcePat_ s st p t)
| Wildcard s
| Variable s Name
| ElementsOfArray s (SourcePat_ s st p t)
| OrPattern s (SourcePat_ s st p t) (SourcePat_ s st p t)
| NestedQuery s (SourceQuery_ s st p t)
| Negation s (SourcePat_ s st p t)
| FactId s (Maybe Text) Word64
| TypeSignature s (SourcePat_ s st p t) (Type_ st p t)
| Never s
| IfPattern
{ span :: s
, cond :: SourcePat_ s st p t
, then_ :: SourcePat_ s st p t
, else_ :: SourcePat_ s st p t
}
| FieldSelect s (SourcePat_ s st p t) FieldName RecordOrSum
| Deref s (SourcePat_ s st p t)
| Enum s Text
-- The following forms are introduced by the resolver, and replace
-- the Variable and App forms produced by the parser.
| Clause s s p (SourcePat_ s st p t) SeekSection
| Prim s PrimOp [SourcePat_ s st p t]
deriving (Eq, Show, Generic, Functor)
-- | Should a `seek` call be restricted to a section of the database?
--
-- When performing a query over a stacked database we have three levels
-- * base db
-- * stacked db
-- * writable FactSet
--
-- The writable FactSet is there to store facts from derived predicates
-- generated during the querying.
--
-- This type specifies which of these sections should be be covered in a seek.
data SeekSection
= SeekOnAllFacts -- ^ base + stacked + writable
| SeekOnBase -- ^ base only
| SeekOnStacked -- ^ stacked only
deriving (Eq, Show, Generic)
instance Binary SeekSection
instance (Binary p, Binary t) => Binary (SourcePat_ () () p t)
instance Bifunctor (SourcePat_ s st) where
bimap f g pat = case pat of
Nat s w -> Nat s w
String s t -> String s t
StringPrefix s t -> StringPrefix s t
ByteArray s t -> ByteArray s t
Array s pats -> Array s (fmap (bimap f g) pats)
ArrayPrefix s pats -> ArrayPrefix s (fmap (bimap f g) pats)
Tuple s pats -> Tuple s (map (bimap f g) pats)
Struct s fields -> Struct s (map (bimap f g) fields)
App s l r -> App s (bimap f g l) (map (bimap f g) r)
KeyValue s k v -> KeyValue s (bimap f g k) (bimap f g v)
Elements s pat -> Elements s (bimap f g pat)
All s query -> All s (bimap f g query)
Wildcard s -> Wildcard s
Variable s n -> Variable s n
ElementsOfArray s pat -> ElementsOfArray s (bimap f g pat)
OrPattern s l r -> OrPattern s (bimap f g l) (bimap f g r)
NestedQuery s (SourceQuery head stmts ord) ->
NestedQuery s (SourceQuery (fmap (bimap f g) head)
(fmap (bimap f g) stmts) ord)
Negation s pat -> Negation s (bimap f g pat)
FactId s n w -> FactId s n w
TypeSignature s pat ty -> TypeSignature s (bimap f g pat) (bimap f g ty)
Never s -> Never s
IfPattern s a b c -> IfPattern s (bimap f g a) (bimap f g b) (bimap f g c)
FieldSelect s pat field q -> FieldSelect s (bimap f g pat) field q
Deref s pat -> Deref s (bimap f g pat)
Enum s f -> Enum s f
Clause sPat sPred p pat rng -> Clause sPat sPred (f p) (bimap f g pat) rng
Prim s p pats -> Prim s p (fmap (bimap f g) pats)
instance Bifoldable (SourcePat_ s st) where
bifoldMap f g = \case
Nat{} -> mempty
String{} -> mempty
StringPrefix{} -> mempty
ByteArray{} -> mempty
Array _ pats -> foldMap (bifoldMap f g) pats
ArrayPrefix _ pats -> foldMap (bifoldMap f g) pats
Tuple _ pats -> foldMap (bifoldMap f g) pats
Struct _ fields -> foldMap (bifoldMap f g) fields
App _ l r -> foldMap (bifoldMap f g) (l:r)
KeyValue _ k v -> bifoldMap f g k <> bifoldMap f g v
Elements _ pat -> bifoldMap f g pat
All _ query -> bifoldMap f g query
Wildcard{} -> mempty
Variable{} -> mempty
ElementsOfArray _ pat -> bifoldMap f g pat
OrPattern _ l r -> bifoldMap f g l <> bifoldMap f g r
NestedQuery _ (SourceQuery head stmts _) ->
foldMap (bifoldMap f g) head <> foldMap (bifoldMap f g) stmts
Negation _ pat -> bifoldMap f g pat
FactId{} -> mempty
TypeSignature _ pat ty -> bifoldMap f g pat <> bifoldMap f g ty
Never{} -> mempty
IfPattern _ a b c -> bifoldMap f g a <> bifoldMap f g b <> bifoldMap f g c
FieldSelect _ pat _ _ -> bifoldMap f g pat
Deref _ pat -> bifoldMap f g pat
Enum _ _ -> mempty
Clause _ _ p pat _ -> f p <> bifoldMap f g pat
Prim _ _ pats -> foldMap (bifoldMap f g) pats
data Field s st p t = Field FieldName (SourcePat_ s st p t)
deriving (Eq, Show, Generic, Functor)
instance (Binary p, Binary t) => Binary (Field () () p t)
instance Bifunctor (Field s st) where
bimap f g (Field n pat) = Field n (bimap f g pat)
instance Bifoldable (Field s st) where
bifoldMap f g (Field _ pat) = bifoldMap f g pat
-- | Primitive operations
data PrimOp
= PrimOpToLower
| PrimOpLength
| PrimOpZip
| PrimOpConcat
| PrimOpReverse
| PrimOpSize
| PrimOpRelToAbsByteSpans
| PrimOpUnpackByteSpans
| PrimOpGtNat
| PrimOpGeNat
| PrimOpLtNat
| PrimOpLeNat
| PrimOpNeNat
| PrimOpAddNat
| PrimOpNeExpr
deriving (Eq, Show, Generic)
instance Binary PrimOp
sourcePatSpan :: SourcePat_ s st p t -> s
sourcePatSpan = \case
Nat s _ -> s
String s _ -> s
StringPrefix s _ -> s
ByteArray s _ -> s
Array s _ -> s
ArrayPrefix s _ -> s
Tuple s _ -> s
Struct s _ -> s
App s _ _ -> s
KeyValue s _ _ -> s
Elements s _ -> s
All s _ -> s
Wildcard s -> s
Variable s _ -> s
ElementsOfArray s _ -> s
OrPattern s _ _ -> s
IfPattern s _ _ _ -> s
NestedQuery s _ -> s
Negation s _ -> s
FactId s _ _ -> s
TypeSignature s _ _ -> s
Never s -> s
FieldSelect s _ _ _ -> s
Deref s _ -> s
Enum s _ -> s
Clause s _ _ _ _ -> s
Prim s _ _ -> s
-- -----------------------------------------------------------------------------
-- Types
-- | A Glean Type
data Type_ srcspan pref tref
-- Native types
= ByteTy
| NatTy
| StringTy
| ArrayTy (Type_ srcspan pref tref)
| RecordTy [FieldDef_ srcspan pref tref]
| SumTy [FieldDef_ srcspan pref tref]
| SetTy (Type_ srcspan pref tref)
| PredicateTy srcspan pref
| NamedTy srcspan tref
-- Derived types. These appear in the source language, but are
-- translated into the native types above internally. They also
-- act as hints to the code generators, e.g. maybe translates to
-- Thrift's optional and enum translates to Thrift's enum.
| MaybeTy (Type_ srcspan pref tref)
-- maybe T => { nothing | just : T }
| EnumeratedTy [Name]
-- enum { a | b } => { a : {}, b : {} }
| BooleanTy
-- bool => { false : {} | true : {} }
-- These are used during typechecking only
| TyVar {-# UNPACK #-}!Int
| HasTy (Map Name (Type_ srcspan pref tref))
!(Maybe RecordOrSum) {-# UNPACK #-}!Int
-- HasTy { field:type .. } R X
-- Constrains X to be a record or sum type containing at least
-- the given fields/types. X can only be instantiated
-- with a type containing a superset of those fields: either
-- a bigger HasTy or a RecordTy/SumTy.
-- R is
-- Just Record -> type must be a record
-- Just Sum -> type must be a sum type
-- Nothing -> type can be either a RecordTy or a SumTy
| HasKey (Type_ srcspan pref tref) {-# UNPACK #-}!Int
-- HasKey K X
-- A type variable X that is constrained to be a predicate
-- type with key K
| ElementsOf (Type_ srcspan pref tref) {-# UNPACK #-}!Int
-- ElementsOf T X
-- A type variable that is either set T or [T]
deriving (Eq, Show, Functor, Foldable, Generic)
data RecordOrSum = Record | Sum
deriving (Eq, Show, Generic)
instance Binary RecordOrSum
instance (Binary pref, Binary tref) => Binary (Type_ () pref tref)
instance Bifunctor (Type_ s) where
bimap f g = \case
ByteTy -> ByteTy
NatTy -> NatTy
StringTy -> StringTy
ArrayTy ty -> ArrayTy $ bimap f g ty
RecordTy xs -> RecordTy $ bimap f g <$> xs
SumTy xs -> SumTy $ bimap f g <$> xs
SetTy ty -> SetTy $ bimap f g ty
PredicateTy s pref -> PredicateTy s (f pref)
NamedTy s tref -> NamedTy s (g tref)
MaybeTy ty -> MaybeTy (bimap f g ty)
EnumeratedTy xs -> EnumeratedTy xs
BooleanTy -> BooleanTy
TyVar x -> TyVar x
HasTy m r x -> HasTy (bimap f g <$> m) r x
HasKey ty x -> HasKey (bimap f g ty) x
ElementsOf ty x -> ElementsOf (bimap f g ty) x
instance Bifoldable (Type_ s) where
bifoldr f g r = \case
ByteTy -> r
NatTy -> r
StringTy -> r
ArrayTy ty -> bifoldr f g r ty
RecordTy xs -> foldr (flip $ bifoldr f g) r xs
SumTy xs -> foldr (flip $ bifoldr f g) r xs
SetTy ty -> bifoldr f g r ty
PredicateTy _ pref -> f pref r
NamedTy _ tref -> g tref r
MaybeTy ty -> bifoldr f g r ty
EnumeratedTy _ -> r
BooleanTy -> r
TyVar _ -> r
HasTy m _ _ -> foldr (flip $ bifoldr f g) r m
HasKey ty _ -> bifoldr f g r ty
ElementsOf ty _ -> bifoldr f g r ty
{- Note [Types]
There are three main instantiations of `Type_` used throughout
Glean:
> type SourceType = Type_ SourceRef SourceRef
These are the types from the parser. Predicates and types may be
unqualified and don't necessarily have versions.
> type Type = Type_ PredicateId TypeId
These are the types after name resolution
(Glean.Schema.Resolve). Predicates and Types are fully qualified and
refer to specific hashes.
> type RTS.Type = Type_ PidRef ExpandedType
(see 'Glean.RTS.Type')
These are the types that relate to a particular DB, and are
constructed when a schema is loaded in `Glean.Database.Schema`.
* Predicates have a particular 'Pid'
* Named types are expanded (but we can still see them in the AST)
* A 'RTS.Type' can be converted into a pure representation ('Rep')
using 'repType'
-}
-- -----------------------------------------------------------------------------
-- Schemas and definitions
data FieldDef_ st pref tref = FieldDef
{ fieldDefName :: Name
, fieldDefType :: Type_ st pref tref
}
deriving (Eq, Show, Functor, Foldable, Generic)
instance (Binary pref, Binary tref)
=> Binary (FieldDef_ () pref tref)
instance Bifunctor (FieldDef_ st) where
bimap f g (FieldDef n ty) = FieldDef n $ bimap f g ty
instance Bifoldable (FieldDef_ st) where
bifoldMap f g (FieldDef _ ty) = bifoldMap f g ty
tupleField :: Text
tupleField = "tuplefield"
-- | A definition of a named type
data TypeDef_ st pref tref = TypeDef
{ typeDefRef :: tref
, typeDefType :: Type_ st pref tref
, typeDefSrcSpan :: st
}
deriving Eq
-- | A definition of a predicate
data PredicateDef_ s st pref tref = PredicateDef
{ predicateDefRef :: pref
, predicateDefKeyType :: Type_ st pref tref
, predicateDefValueType :: Type_ st pref tref
, predicateDefDeriving :: DerivingInfo (SourceQuery_ s st pref tref)
, predicateDefSrcSpan :: s
}
deriving Eq
data DerivingDef_ s st pref tref = DerivingDef
{ derivingDefRef :: pref
, derivingDefDeriveInfo :: DerivingInfo (SourceQuery_ s st pref tref)
, derivingDefSrcSpan :: s
}
deriving Eq
-- | Globally unique identifier for a predicate. This is not the same
-- as a Pid, which is unique only within a particular DB.
data PredicateId = PredicateId
{ predicateIdRef :: PredicateRef -- ^ e.g. python.Name.1
, predicateIdHash :: {-# UNPACK #-} !Hash
} deriving (Ord, Generic, Show)
instance Hashable PredicateId where
hashWithSalt s (PredicateId _ h) = hashFingerprint s h
instance Eq PredicateId where
PredicateId _ a == PredicateId _ b = a == b
instance Binary PredicateRef where
put (PredicateRef a b) = put a >> put b
get = PredicateRef <$> get <*> get
instance Binary PredicateId
-- TODO maybe just serialize the hash?
-- | Globally unique identifier for a type.
data TypeId = TypeId
{ typeIdRef :: TypeRef -- ^ e.g. python.Declaration.1
, typeIdHash :: {-# UNPACK #-} !Hash
} deriving (Ord, Generic, Show)
instance Hashable TypeId where
hashWithSalt s (TypeId _ h) = hashFingerprint s h
instance Eq TypeId where
TypeId _ a == TypeId _ b = a == b
-- Used by query compilation
tempPredicateId :: PredicateId
tempPredicateId = PredicateId (PredicateRef "_tmp_" 0) hash0
instance Binary TypeRef where
put (TypeRef a b) = put a >> put b
get = TypeRef <$> get <*> get
instance Binary TypeId
-- TODO maybe just serialize the hash?
-- | How to derive a predicate
data DerivingInfo q
= NoDeriving
| Derive DeriveWhen q
deriving (Eq, Functor, Foldable, Show, Generic)
instance Binary q => Binary (DerivingInfo q)
data DeriveWhen
= DeriveOnDemand
-- ^ derived whenever this predicate is queried. Facts of this
-- predicate are not expected to be stored in the DB.
| DerivedAndStored
-- ^ derived eagerly and stored in the DB. By default, queries for
-- this predicate will search the DB, just like underived
-- predicates.
| DeriveIfEmpty
-- ^ derived only when the DB has no facts of this predicate.
-- This is used to add derivations for backwards compatibility
-- during a schema migration.
deriving (Eq, Show, Generic)
instance Binary DeriveWhen
-- Source (parsed) abstract syntax
type SourcePat' s st = SourcePat_ s st SourceRef SourceRef
type SourceStatement' s st = SourceStatement_ s st SourceRef SourceRef
type SourceQuery' s st = SourceQuery_ s st SourceRef SourceRef
type SourceDerivingInfo' s = DerivingInfo (SourceQuery' s s)
type SourcePredicateDef' s = PredicateDef_ s s SourceRef SourceRef
type SourceTypeDef' s = TypeDef_ s SourceRef SourceRef
type DerivingDef' s = DerivingDef_ s s SourceRef SourceRef
type SourceType' st = Type_ st SourceRef SourceRef
type Type' st = Type_ st PredicateId TypeId
type SourcePat = SourcePat' SrcSpan SrcSpan
type SourceStatement = SourceStatement' SrcSpan SrcSpan
type SourceQuery = SourceQuery' SrcSpan SrcSpan
type SourceType = Type_ SrcSpan SourceRef SourceRef
type SourceFieldDef = FieldDef_ SrcSpan SourceRef SourceRef
type SourceTypeDef = TypeDef_ SrcSpan SourceRef SourceRef
type SourcePredicateDef = SourcePredicateDef' SrcSpan
type SourceDerivingInfo = SourceDerivingInfo' SrcSpan
type SourceSchemas = SourceSchemas_ SrcSpan
type SourceSchema = SourceSchema_ SrcSpan
type SourceEvolves = SourceEvolves_ SrcSpan
type SourceDecl = SourceDecl_ SrcSpan
type Statement_ p t = SourceStatement_ SrcSpan SrcSpan p t
type Query_ p t = SourceQuery_ SrcSpan SrcSpan p t
data SourceEvolves_ s = SourceEvolves
{ evolvesSpan :: s
, evolvesNew :: SourceRef
, evolvesOld :: SourceRef
}
deriving (Eq)
-- | A 'schema' declaration
data SourceSchema_ s = SourceSchema
{ schemaName :: SourceRef
, schemaInherits :: [SourceRef]
, schemaDecls :: [SourceDecl_ s]
, schemaSrcSpan :: s
}
deriving (Eq)
data SourceSchemas_ s = SourceSchemas
{ srcAngleVersion :: AngleVersion
, srcSchemas :: [SourceSchema_ s]
, srcEvolves :: [SourceEvolves_ s]
}
deriving (Eq)
data SourceDecl_ s
= SourceImport SourceRef s
| SourcePredicate (SourcePredicateDef' s)
| SourceType (SourceTypeDef' s)
| SourceDeriving (DerivingDef' s)
deriving (Eq)
-- Abstract syntax with global Ids
type Type = Type_ SrcSpan PredicateId TypeId
type FieldDef = FieldDef_ SrcSpan PredicateId TypeId
type TypeDef = TypeDef_ SrcSpan PredicateId TypeId
type PredicateDef = PredicateDef_ SrcSpan SrcSpan PredicateId TypeId
type PredicateDef' s st = PredicateDef_ s st PredicateId TypeId
type FieldDef' st = FieldDef_ st PredicateId TypeId
-- -----------------------------------------------------------------------------
-- | Version of the syntax. This is required so that we can change the
-- syntax while still allowing DBs that contain a schema with the old
-- syntax to be understood.
newtype AngleVersion = AngleVersion Int
deriving (Eq, Ord)
deriving newtype (Pretty)
-- version 8:
-- - added set constructs
-- version 9:
-- - added dot syntax
-- version 10:
-- - optional versions in `import`, `evolves`, inheritance
-- version 11:
-- - size primop
-- version 12:
-- - remove support for deriving default
latestSupportedAngleVersion :: AngleVersion
latestSupportedAngleVersion = AngleVersion 5
latestAngleVersion :: AngleVersion
latestAngleVersion = AngleVersion 12
-- -----------------------------------------------------------------------------
-- Pretty-printing
instance Display SourceRef where
display _ (SourceRef name ver) = pretty name <> case ver of
Nothing -> mempty
Just ver -> "." <> pretty ver
instance Display PredicateRef where
display _ = pretty
instance Display TypeRef where
display _ = pretty
instance Display PredicateId where
display opts (PredicateId name hash) =
case predicateStyle opts of
PredicateWithHash -> pretty name <> "." <> pretty (show hash)
PredicateWithoutHash -> pretty name
instance Display TypeId where
display opts (TypeId name hash) =
case predicateStyle opts of
PredicateWithHash -> pretty name <> "." <> pretty (show hash)
PredicateWithoutHash -> pretty name
instance Display (SourceEvolves_ s) where
display opts (SourceEvolves _ new old) =
"schema " <> display opts new <> " evolves " <> display opts old
instance (Display pref, Display tref) => Display (Type_ st pref tref) where
display _ ByteTy = "byte"
display _ NatTy = "nat"
display _ StringTy = "string"
display opts (ArrayTy ty) = "[" <> display opts ty <> "]"
display opts (RecordTy fields) =
sep
[ nest 2 $ vsep $ "{" : punctuate "," (map (display opts) fields)
, "}" ]
display opts (SumTy fields) =
sep
[ nest 2 $ vsep $ "{" : map ((<> " |") . display opts) fields
, "}" ]
display opts (SetTy ty) = "set " <> displayAtom opts ty
display opts (PredicateTy _ p) = display opts p
display opts (NamedTy _ t) = display opts t
display opts (MaybeTy t) = "maybe" <+> displayAtom opts t
display _ (EnumeratedTy names) =
sep
[ nest 2 $ vsep $ "enum {" : map (<> " |") (map pretty names)
, "}" ]
display _ BooleanTy = "bool"
display _ (TyVar n) = "T" <> pretty n
display opts (HasTy m rec x)
| Just Sum <- rec =
sep
[ nest 2 $ vsep $ "{" : intersperse "|" (map doField (Map.toList m))
, "|", "T" <> pretty x, "}" ]
| otherwise =
sep
[ nest 2 $ vsep $ "{" : map (<> ",") (map doField (Map.toList m))
, "T" <> pretty x, "}" ]
where
doField (n, ty) = pretty n <> " : " <> display opts ty
display opts (HasKey ty x) =
"T" <> pretty x <> parens (display opts ty)
display opts (ElementsOf ty x) =
"T" <> pretty x <> brackets (display opts ty)
displayAtom opts t = case t of
MaybeTy{} -> parens $ display opts t
EnumeratedTy{} -> parens $ display opts t
SetTy{} -> parens $ display opts t
_other -> display opts t
instance (Display pref, Display tref) => Display (FieldDef_ st pref tref) where
display opts (FieldDef n ty) = pretty n <> " : " <> displayAtom opts ty
instance (Display pref, Display tref) =>
Display (PredicateDef_ s st pref tref) where
display opts PredicateDef{..} =
hang 2 $ sep $
[ "predicate" <+> display opts predicateDefRef <+> ":"
, display opts predicateDefKeyType
] ++
(case predicateDefValueType of
RecordTy [] -> []
_other -> [ "->" <+> display opts predicateDefValueType ]) ++
(case predicateDefDeriving of
Derive DerivedAndStored query -> [ "stored", display opts query ]
Derive _ query -> [ display opts query ]
_other -> [])
instance (Display pref, Display tref) => Display (TypeDef_ s pref tref) where
display opts TypeDef{..} =
hang 2 $ sep
[ "type" <+> display opts typeDefRef <+> "="
, display opts typeDefType
]
instance Display SourceSchemas where
display opts SourceSchemas{..} = vcat $
("version:" <+> pretty srcAngleVersion)
: map (display opts) srcSchemas <> map (display opts) srcEvolves
instance Display SourceSchema where
display opts SourceSchema{..} = vcat
[ "schema" <+> display opts schemaName <>
case schemaInherits of
[] -> mempty
_ -> " : " <> hcat (punctuate "," (map (display opts) schemaInherits))
<> " {"
, vcat (map (display opts) schemaDecls)
, "}"
]
instance Display SourceDecl where
display opts (SourceImport name _) = "import " <> display opts name
display opts (SourcePredicate def) = display opts def
display opts (SourceType def) = display opts def
display opts (SourceDeriving DerivingDef{..}) =
hang 2 $ sep ["derive "
<> display opts derivingDefRef, display opts derivingDefDeriveInfo]
instance Display q => Display (DerivingInfo q) where
display _ NoDeriving = mempty
display opts (Derive DeriveOnDemand q) = display opts q
display opts (Derive DerivedAndStored q) = "stored" <+> display opts q
display opts (Derive DeriveIfEmpty q) = "default" <+> display opts q
-- ---------------------------------------------------------------------------
-- Display printing queries
class IsWild pat where
isWild :: pat -> Bool
instance IsWild (SourcePat_ s st p t) where
isWild Wildcard{} = True
isWild _ = False
-- | Types that represent the source location of a term in the AST
class (Pretty a, Pretty (Loc a)) => IsSrcSpan a where
type Loc a :: *
startLoc :: a -> Loc a
endLoc :: a -> Loc a
mkSpan :: Loc a -> Loc a -> a
-- space encompassing from start of first span to end of second.
spanBetween :: IsSrcSpan a => a -> a-> a
spanBetween x y = mkSpan (startLoc x) (endLoc y)
instance IsSrcSpan SrcSpan where
type Loc SrcSpan = SrcLoc
startLoc = spanStart
endLoc = spanEnd
mkSpan = SrcSpan
instance Display SrcSpan where
display opts s =
display opts (spanStart s)
<> pretty (" - " :: String)
<> display opts (spanEnd s)
instance Pretty SrcSpan where
pretty = displayDefault
instance Display SrcLoc where
display _ (SrcLoc line col) =
"line " <> pretty line <> ", column " <> pretty col
instance Pretty SrcLoc where
pretty = displayDefault
instance (Display p, Display t) => Pretty (SourcePat_ s st p t) where
pretty = displayDefault
instance (Display p, Display t) => Display (SourcePat_ s st p t) where
display _ (Nat _ w) = pretty w
display _ (String _ str) =
pretty (Text.decodeUtf8 (BL.toStrict (Aeson.encode (Aeson.String str))))
display opts (StringPrefix s str) =
display opts (String s str :: SourcePat_ s st p t) <> ".."
display _ (ByteArray _ b) = pretty (show b)
display opts (Array _ pats) =
brackets $ hsep (punctuate "," (map (display opts) pats))
display opts (ArrayPrefix _ pats) =
encloseSep "[" ", ..]" "," (map (display opts) $ toList pats)
display opts (Tuple _ pats) =
braces $ hsep (punctuate "," (map (display opts) pats))
display opts (Struct _ fs) = cat [ nest 2 $ cat [ "{", fields fs], "}"]
where
fields = sep . punctuate "," . map field
field (Field name pat) = pretty name <+> "=" <+> display opts pat
display opts (App _ l pats) =
display opts l <+> hsep (punctuate " " (map (displayAtom opts) pats))
display opts (KeyValue _ k v) =
displayAtom opts k <+> "->" <+> displayAtom opts v
display opts (Elements _ pat) =
"elements" <+> parens (display opts pat)
display opts (All _ query) =
"all" <+> parens (display opts query)
display _ (Wildcard _) = "_"
display _ (Variable _ name) = pretty name
display opts (ElementsOfArray _ pat) = displayAtom opts pat <> "[..]"
display opts (OrPattern _ lhs rhs) =
sep [displayAtom opts lhs <+> "|", displayAtom opts rhs]
display opts (IfPattern _ cond then_ else_) = sep
[ nest 2 $ sep ["if", displayAtom opts cond ]
, nest 2 $ sep ["then", displayAtom opts then_]
, nest 2 $ sep ["else", displayAtom opts else_]
]
display opts (NestedQuery _ q) = parens $ display opts q
display opts (Negation _ q) = "!" <> parens (display opts q)
display _ (FactId _ Nothing n) = "$" <> pretty n
display _ (FactId _ (Just p) n) = "$" <> pretty p <+> pretty n
display opts (TypeSignature _ p t) =
displayAtom opts p <+> ":" <+> display opts t
display _ (Never _) = "never"
display opts (Clause _ _ p pat rng) =
display opts p <> prng <+> displayAtom opts pat
where prng = case rng of
SeekOnBase -> "#old"
SeekOnStacked -> "#new"
_ -> mempty
display opts (Prim _ p pats) =
display opts p <+> hsep (punctuate " " (map (displayAtom opts) pats))
display opts (FieldSelect _ pat field q) =
displayAtom opts pat <> "." <> pretty field <>
case q of
Sum -> "?"
Record -> mempty
display opts (Deref _ pat) =
displayAtom opts pat <> ".*"
display _ (Enum _ f) = pretty f
displayAtom opts pat = case pat of
App{} -> parens $ display opts pat
KeyValue{} -> parens $ display opts pat
OrPattern{} -> parens $ display opts pat
IfPattern{} -> parens $ display opts pat
TypeSignature{} -> parens $ display opts pat
Nat{} -> display opts pat
String{} -> display opts pat
StringPrefix{} -> display opts pat
ByteArray{} -> display opts pat
Array{} -> display opts pat
ArrayPrefix{} -> display opts pat
Tuple{} -> display opts pat
Struct{} -> display opts pat
ElementsOfArray{} -> parens $ display opts pat
Elements{} -> display opts pat
All{} -> parens $ display opts pat
Wildcard{} -> display opts pat
Variable{} -> display opts pat
NestedQuery{} -> display opts pat
Negation{} -> display opts pat
FactId{} -> display opts pat
Never{} -> display opts pat
Clause{} -> parens $ display opts pat
Prim{} -> parens $ display opts pat
FieldSelect{} -> display opts pat
Deref{} -> display opts pat
Enum _ _ -> display opts pat
instance (Display p, Display t) => Display (SourceQuery_ s st p t) where
display opts (SourceQuery maybeHead stmts _ord) = case stmts of
[] -> maybe mempty (display opts) maybeHead
_ -> case maybeHead of
Just head -> hang 2 (sep (display opts head <+> "where" : pstmts))
Nothing -> sep pstmts
where
pstmts = punctuate ";" (map (display opts) stmts)
instance (Display p, Display t) => Display (SourceStatement_ s st p t) where
display opts (SourceStatement lhs rhs) = displayStatement opts lhs rhs
displayStatement
:: (IsWild pat, Display pat)
=> DisplayOpts
-> pat
-> pat
-> Doc ann
displayStatement opts lhs rhs
| isWild lhs = display opts rhs
| otherwise = hang 2 $ sep [display opts lhs <+> "=", display opts rhs]
instance Display PrimOp where
display _ PrimOpToLower = "prim.toLower"
display _ PrimOpLength = "prim.length"
display _ PrimOpZip = "prim.zip"
display _ PrimOpConcat = "prim.concat"
display _ PrimOpReverse = "prim.reverse"
display _ PrimOpSize = "prim.size"
display _ PrimOpRelToAbsByteSpans = "prim.relToAbsByteSpans"
display _ PrimOpUnpackByteSpans = "prim.unpackByteSpans"
display _ PrimOpGtNat = "prim.gtNat"
display _ PrimOpGeNat = "prim.geNat"
display _ PrimOpLtNat = "prim.ltNat"
display _ PrimOpLeNat = "prim.leNat"
display _ PrimOpNeNat = "prim.neNat"
display _ PrimOpAddNat = "prim.addNat"
display _ PrimOpNeExpr = "prim.neExpr"
-- -----------------------------------------------------------------------------
-- Removing source locations from the AST
rmLocSchemas :: SourceSchemas_ a -> SourceSchemas_ ()
rmLocSchemas (SourceSchemas version schemas evolves) =
SourceSchemas version (rmLocSchema <$> schemas) (rmLocEvolves <$> evolves)
rmLocSchema :: SourceSchema_ a -> SourceSchema_ ()
rmLocSchema (SourceSchema name inherits decls _) =
SourceSchema name inherits (rmLocDecl <$> decls) ()
rmLocEvolves :: SourceEvolves_ a -> SourceEvolves_ ()
rmLocEvolves (SourceEvolves _ a b) = SourceEvolves () a b
rmLocDecl :: SourceDecl_ s -> SourceDecl_ ()
rmLocDecl = \case
SourceImport name _ -> SourceImport name ()
SourcePredicate pred -> SourcePredicate $ rmLocPredDef pred
SourceType typeDef -> SourceType $ rmLocTypeDef typeDef
SourceDeriving DerivingDef{..} -> SourceDeriving $ DerivingDef
derivingDefRef (rmLocQuery <$> derivingDefDeriveInfo) ()
rmLocPredDef :: PredicateDef_ s st p t -> PredicateDef_ () () p t
rmLocPredDef PredicateDef{..} = PredicateDef {
predicateDefRef = predicateDefRef,
predicateDefKeyType = rmLocType predicateDefKeyType,
predicateDefValueType = rmLocType predicateDefValueType,
predicateDefDeriving = rmLocQuery <$> predicateDefDeriving,
predicateDefSrcSpan = ()
}
rmLocQuery :: SourceQuery_ s st p t -> SourceQuery_ () () p t
rmLocQuery (SourceQuery mhead stmts ord) =
SourceQuery (rmLocPat <$> mhead) (rmLocStatement <$> stmts) ord
rmLocStatement :: SourceStatement_ s st p t -> SourceStatement_ () () p t
rmLocStatement (SourceStatement x y) =
SourceStatement (rmLocPat x) (rmLocPat y)
rmLocTypeDef :: TypeDef_ s p t -> TypeDef_ () p t
rmLocTypeDef (TypeDef tref ty _) = TypeDef tref (rmLocType ty) ()
rmLocType :: Type_ st p t -> Type_ () p t
rmLocType = \case
ByteTy -> ByteTy
NatTy -> NatTy
StringTy -> StringTy
ArrayTy ty -> ArrayTy $ rmLocType ty
RecordTy xs -> RecordTy $ rmLocFieldDef <$> xs
SumTy xs -> SumTy $ rmLocFieldDef <$> xs
SetTy ty -> SetTy $ rmLocType ty
PredicateTy _ pref -> PredicateTy () pref
NamedTy _ tref -> NamedTy () tref
MaybeTy ty -> MaybeTy $ rmLocType ty
EnumeratedTy xs -> EnumeratedTy xs
BooleanTy -> BooleanTy
TyVar x -> TyVar x
HasTy m r x -> HasTy (rmLocType <$> m) r x
HasKey ty x -> HasKey (rmLocType ty) x
ElementsOf ty x -> ElementsOf (rmLocType ty) x
rmLocFieldDef :: FieldDef_ s p t -> FieldDef_ () p t
rmLocFieldDef (FieldDef n ty) = FieldDef n $ rmLocType ty
rmLocPat :: SourcePat_ s st p t -> SourcePat_ () () p t
rmLocPat = \case
Nat _ x -> Nat () x
String _ x -> String () x
StringPrefix _ x -> StringPrefix () x
ByteArray _ x -> ByteArray () x
Array _ xs -> Array () (rmLocPat <$> xs)
ArrayPrefix _ xs -> ArrayPrefix () (rmLocPat <$> xs)
Tuple _ xs -> Tuple () (rmLocPat <$> xs)
Struct _ xs -> Struct () (rmLocField <$> xs)
App _ x xs -> App () (rmLocPat x) (rmLocPat <$> xs)
KeyValue _ x y -> KeyValue () (rmLocPat x) (rmLocPat y)
Elements _ pat -> Elements () (rmLocPat pat)
All _ query -> All () (rmLocPat query)
Wildcard _ -> Wildcard ()
Never _ -> Never ()
Variable _ v -> Variable () v
ElementsOfArray _ x -> ElementsOfArray () (rmLocPat x)
OrPattern _ x y -> OrPattern () (rmLocPat x) (rmLocPat y)
IfPattern _ x y z -> IfPattern () (rmLocPat x) (rmLocPat y) (rmLocPat z)
Negation _ x -> Negation () (rmLocPat x)
NestedQuery _ query -> NestedQuery () $ rmLocQuery query
FactId _ x y -> FactId () x y
TypeSignature _ x t -> TypeSignature () (rmLocPat x) (rmLocType t)
Clause _ _ x y rng -> Clause () () x (rmLocPat y) rng
Prim _ p ps -> Prim () p (rmLocPat <$> ps)
FieldSelect _ pat field q -> FieldSelect () (rmLocPat pat) field q
Deref _ pat -> Deref () (rmLocPat pat)
Enum _ f -> Enum () f
rmLocField :: Field s st p t -> Field () () p t
rmLocField (Field name pat) =
Field name (rmLocPat pat)
-- Remove spans from type refs only. Useful when
-- the two span types are different (s != st), e.g., s = SrcSpan, st = ()
rmTypeLocPredDef :: PredicateDef_ s st p t -> PredicateDef_ s () p t
rmTypeLocPredDef pred = pred
{ predicateDefKeyType = rmLocType $ predicateDefKeyType pred
, predicateDefValueType = rmLocType $ predicateDefValueType pred
, predicateDefDeriving = rmTypeLocQuery <$> predicateDefDeriving pred}
rmTypeLocQuery :: SourceQuery_ s st p t -> SourceQuery_ s () p t
rmTypeLocQuery (SourceQuery mhead stmts ord) =
SourceQuery (rmTypeLocPat <$> mhead) (rmTypeLocStatement <$> stmts) ord
rmTypeLocStatement :: SourceStatement_ s st p t -> SourceStatement_ s () p t
rmTypeLocStatement (SourceStatement x y) =
SourceStatement (rmTypeLocPat x) (rmTypeLocPat y)
rmTypeLocPat :: SourcePat_ s st p t -> SourcePat_ s () p t
rmTypeLocPat pat = case pat of
Nat s x -> Nat s x
String s x -> String s x
StringPrefix s x -> StringPrefix s x
ByteArray s x -> ByteArray s x
TypeSignature s x t -> TypeSignature s (rmTypeLocPat x) (rmLocType t)
Array s xs -> Array s (rmTypeLocPat <$> xs)
ArrayPrefix s xs -> ArrayPrefix s (rmTypeLocPat <$> xs)
Tuple s xs -> Tuple s (rmTypeLocPat <$> xs)
Struct s xs -> Struct s (rmTypeLocField <$> xs)
App s x xs -> App s (rmTypeLocPat x) (rmTypeLocPat <$> xs)
KeyValue s x y -> KeyValue s (rmTypeLocPat x) (rmTypeLocPat y)
Elements s pat -> Elements s (rmTypeLocPat pat)
All s query -> All s (rmTypeLocPat query)
Wildcard s -> Wildcard s
Never s -> Never s
Variable s v -> Variable s v
ElementsOfArray s x -> ElementsOfArray s (rmTypeLocPat x)
OrPattern s x y -> OrPattern s (rmTypeLocPat x) (rmTypeLocPat y)
IfPattern s x y z ->
IfPattern s (rmTypeLocPat x) (rmTypeLocPat y) (rmTypeLocPat z)
Negation s x -> Negation s (rmTypeLocPat x)
NestedQuery s query -> NestedQuery s $ rmTypeLocQuery query
FactId s x y -> FactId s x y
Clause s ss x y rng -> Clause s ss x (rmTypeLocPat y) rng
Prim s p ps -> Prim s p (rmTypeLocPat <$> ps)
FieldSelect s pat field q -> FieldSelect s (rmTypeLocPat pat) field q
Deref s pat -> Deref s (rmTypeLocPat pat)
Enum s f -> Enum s f
rmTypeLocField :: Field s st p t -> Field s () p t
rmTypeLocField (Field name pat) =
Field name (rmTypeLocPat pat)
-- -----------------------------------------------------------------------------
-- Describing the kind of pattern
class Describe a where
describe :: a -> Doc ann
instance Describe (SourcePat_ s st p t) where
describe = \case
Nat {} -> "a nat"
String {} -> "a string"
StringPrefix {} -> "a string prefix"
ByteArray {} -> "a byte array"
Array {} -> "an array"
ArrayPrefix {} -> "an array prefix"
Tuple {} -> "a tuple"
Struct {} -> "a struct"
App {} -> "an application"
KeyValue {} -> "a key value pattern"
All {} -> "a set with all the results of its argument"
Wildcard {} -> "a wildcard pattern"
Never {} -> "a never pattern"
Variable {} -> "a variable"
ElementsOfArray {} -> "an element of an array"
Elements {} -> "an element of a set"
OrPattern {} -> "an or pattern"
IfPattern {} -> "an if pattern"
Negation {} -> "a negation"
NestedQuery {} -> "a nested query"
FactId {} -> "a fact id"
TypeSignature {} -> "a type signature"
Clause {} -> "a clause"
Prim {} -> "a primitive function"
FieldSelect{} -> "a record field"
Deref{} -> "a dereference"
Enum{} -> "an enum value"
instance Describe SrcSpan where
describe _ = "a source span"
instance Describe SrcLoc where
describe _ = "a source location"