{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeOperators #-} -------------------------------------------------------------------------------- -- | -- Module : Cubix.Essentials -- Copyright : (c) 2020 James Koppel -- License : BSD3 -- -- This is a beginner-friendly package containing the most common functions and -- types needed by Cubix programs. It is built as a companion to the Cubix tutorial, -- though we explain many things in both places. -- -- __Guide to using this file__ -- * __Strongly recommend__: Click "Collapse All Instances" in the top-right corner -- * For newcomers: Look at the examples given, not at the types -- * This file is not the authoritative source for any of its exports. Some -- typeclasses have methods hidden here. Some functions are exported -- with more-specific type signatures that are easier to understand. -- -------------------------------------------------------------------------------- module Cubix.Essentials ( -- * Core representation -- -- ** Language fragments -- $fragments -- TODO (**TODO**): Discuss smart constructors somewhere deriveAll -- ** Signatures: Combining fragments -- $sums , O.Sum -- ** Terms -- | Terms are how we put stuff together , Term , inject -- ** Dealing with sums , (O.:-<:) , O.All , caseCxt -- ** Higher topics involving sums/tems -- *** Sort injections , InjF(injF, projF) -- *** Labeled nodes , Label , TermLab -- *** Common typeclassess -- -- | These are analogues of standard typeclasses, but for sorted unfixed datatypes. -- You are unlikely to use methods in these classes directly, but -- you may frequently invoke functions that require them. You may -- wind up writing many constraints that use these, likely combined with the `All` -- constructor. -- , O.HFunctor , O.HFoldable , O.HTraversable , O.EqHF , O.OrdHF , O.ShowHF -- * Manipulating terms , project -- ** Dealing with annotations , project' -- ** Dealing with containers , InsertF(..) , ExtractF(..) -- ** Traversals -- *** Without strategy combinators -- | Cubix inherits from @compdata@ two elementary traversal functions. , query , transform -- *** With strategy combinators -- -- | The standard @`(>=>)`@ operator is also -- useful for sequentially combining `RewriteM`'s. , RewriteM , (>+>) , addFail , promoteRF , promoteR , alltdR , prunetdR -- * Languages -- ** Signatures -- | -- The primary language signatures in Cubix are `MCSig`, `MJavaSig`, `MJSSig`, `MLuaSig`, and `MPythonSig`. -- The "M" stands for "modular." -- -- These are all long, auto-generated definitions consisting of every language -- fragment in the language (often over 80). We re-export them here, but with their definitions hidden. , MCSig , MJavaSig , MJSSig , MLuaSig , MPythonSig -- ** Terms , MCTerm , MJavaTerm , MJSTerm , MLuaTerm , MPythonTerm -- ** Labeled terms , MCTermLab , MJavaTermLab , MJSTermLab , MLuaTermLab , MPythonTermLab -- ** Parsing / pretty-printing , ParseFile(..) , Pretty(pretty) -- * Control-flow graphs -- ** Representation , Cfg , CfgNode , safeLookupCfg , lookupCfg , cfgNodeForTerm -- ** Construction , makeCfg -- CFG-based inserter , MonadCfgInsertion(dominatingPrependFirst) , CfgInserterT , performCfgInsertions ) where --------------------------------------------------- ----- For re-exports --------------------------------------------------- import qualified Data.Comp.Multi as O import Data.Comp.Multi.Strategic import Cubix.Language.Info import Cubix.ParsePretty import qualified Cubix.Language.C.Parametric.Common as C import Cubix.Language.C.Parametric.Common hiding ( MCSig ) import qualified Cubix.Language.Java.Parametric.Common as Java import Cubix.Language.Java.Parametric.Common hiding ( MJavaSig ) import qualified Cubix.Language.JavaScript.Parametric.Common as JS import Cubix.Language.JavaScript.Parametric.Common hiding ( MJSSig ) import qualified Cubix.Language.Lua.Parametric.Common as Lua import Cubix.Language.Lua.Parametric.Common hiding ( MLuaSig ) import qualified Cubix.Language.Python.Parametric.Common as Python import Cubix.Language.Python.Parametric.Common hiding ( MPythonSig ) import Cubix.Language.Parametric.Derive import Cubix.Language.Parametric.InjF import Cubix.Language.Parametric.Semantics.Cfg import Cubix.Language.Parametric.Semantics.CfgInserter import Cubix.Language.Parametric.Syntax --------------------------------------------------- ----- For references --------------------------------------------------- import Control.Monad ( (>=>) ) --------------------------------------------------- ----- For re-exports --------------------------------------------------- import Data.Proxy ( Proxy ) --------------------------------------------------- ----- Longer docs --------------------------------------------------- {- $fragments The first concept is that of a language fragment and signature. Language fragments in Cubix look like this: @ data ExpL data StatementL data Statement e l where Assign :: String -> e ExpL -> Statement e StatementL Seq :: e StatementL -> e StatementL -> Statement e StatementL @ This definition of @Statement@ is called a *language fragment*. It defines the nodes @Assign@ and @Seq@ without any reference to the larger language they are embedded in. The *labels* @StatementL@ and @ExpL@ are *sorts*, categories of terms. Popular languages commonly have a sort for top-level definitions, a sort for lvalues, a sort for import statements, etc. Specifying the sort separately from the language fragment makes it possible to modularly add new statements and expressions to a language definition, which we will demonstrate shortly. Expect to see the kind @(* -> *) -> * -> *@ a lot, the kind of language fragments. When you define a normal datatype (kind @*@) in Haskell, you might suffix it with @deriving (Eq, Ord, Show)@. The equivalent for these higher-kinded language fragments is to derive their higher-kinded equivalents using the `deriveAll` Template Haskell function, e.g.: @ deriveAll [''Statement] @ -} {- $sums Language fragments let one define nodes independent of a larger language. We shall soon show how to combine them into a **signature**. But first, let us define two more language fragments, @Conditional@ and @Exp@. @ data Conditional e l where If :: e ExpL -> e StatementL -> e StatementL -> Conditional e StatementL data Exp e l where VarExp :: String -> Exp e ExpL Add :: e ExpL -> e ExpL -> Exp e ExpL -- other cases omitted @ As a preview, note how @Conditional@ defines a new node @If@ of sort @Statement@. When these fragments are combined into a language, the @If@ node will be able to be included under a @Seq@ node, just as easily as if was defined in the @Statement@ fragment. A *signature* is a collection of language fragments. They take the form of a type-level list. Here is a signature for a language containing all the nodes in the @Statement@, @Conditional@, and @Exp@ fragments. @ type LangSig = '[Statement, Conditional, Exp] @ Signatures have the kind @[(* -> *) -> * -> *]@, another kind you'll encounter frequently. Signatures are used by passing them to the `Sum` constructor, e.g.: @ Sum LangSig @ @Sum LangSig@ has kind @(* -> *) -> * -> *@, the same kind as language fragments. It is conceptually a single language fragment consisting of the combined nodes of @Statement@, @Conditional@, and @Exp@. It could even be placed in another language signature, and nested within another `Sum`, although this use case is not supported. The `Sum` constructor is important to Cubix, but you may not use it directly. More often, you'll use something like @Term LangSig@ --- but note that `Term` is defined using `Sum`. -} ------------------------------------------------------------------------------------------ ---- Haddock has a limitation where hideous kind signatures appear ---- in re-exported functions (at least from a different package). We thus redefine a lot ---- of things here so that the docs look prettier. Does not work for typeclasses, alas. ---- Has the side-effect of nuking the original docstring. ---- ---- While we're at it, we can also simplify some type signatures. ------------------------------------------------------------------------------------------ ---------------- Redefinitions for compdata ---------------------------------------------- type Term fs = O.HFix (O.Sum fs) project' :: (O.RemA f f', s O.:<: f') => O.HFix f i -> Maybe (s (O.HFix f) i) project' :: HFix f i -> Maybe (s (HFix f) i) project' = HFix f i -> Maybe (s (HFix f) i) forall (f :: (* -> *) -> * -> *) (f' :: (* -> *) -> * -> *) (s :: (* -> *) -> * -> *) h (a :: * -> *) i. (RemA f f', s :<: f') => Cxt h f a i -> Maybe (s (Cxt h f a) i) O.project' -- | For full documentaton, see original declaration: `Data.Comp.Multi.Sum.project` -- -- Simpler definition: -- -- @ -- project :: (g O.:-<: fs) => Term fs l -> Maybe (g (Term fs) l) -- @ project :: (g O.:<: f) => O.Cxt h f a l -> Maybe (g (O.Cxt h f a) l) project :: Cxt h f a l -> Maybe (g (Cxt h f a) l) project = Cxt h f a l -> Maybe (g (Cxt h f a) l) forall (g :: (* -> *) -> * -> *) (f :: (* -> *) -> * -> *) h (a :: * -> *). (g :<: f) => NatM Maybe (Cxt h f a) (g (Cxt h f a)) O.project -- | For full documentaton, see original declaration: `Data.Comp.Multi.Ops.caseCxt` caseCxt :: (O.All cxt fs) => Proxy cxt -> (forall f. (cxt f) => f a e -> b) -> O.Sum fs a e -> b caseCxt :: Proxy cxt -> (forall (f :: (* -> *) -> * -> *). cxt f => f a e -> b) -> Sum fs a e -> b caseCxt = Proxy cxt -> (forall (f :: (* -> *) -> * -> *). cxt f => f a e -> b) -> Sum fs a e -> b forall (cxt :: ((* -> *) -> * -> *) -> Constraint) (fs :: [(* -> *) -> * -> *]) (a :: * -> *) e b. All cxt fs => Proxy cxt -> (forall (f :: (* -> *) -> * -> *). cxt f => f a e -> b) -> Sum fs a e -> b O.caseCxt inject :: (g O.:-<: fs) => g (Term fs) l -> Term fs l inject :: g (Term fs) l -> Term fs l inject = g (Term fs) l -> Term fs l forall (g :: (* -> *) -> * -> *) (f :: (* -> *) -> * -> *) h (a :: * -> *). (g :<: f) => g (Cxt h f a) :-> Cxt h f a O.inject -- | For full documentation, see original declaration: `Data.Comp.Multi.Generic.transform` transform :: (O.All O.HFunctor fs) => (forall i. Term fs i -> Term fs i) -> Term fs l -> Term fs l transform :: (forall i. Term fs i -> Term fs i) -> Term fs l -> Term fs l transform = (forall i. Term fs i -> Term fs i) -> Term fs l -> Term fs l forall (f :: (* -> *) -> * -> *). HFunctor f => (HFix f :-> HFix f) -> HFix f :-> HFix f O.transform -- | For full documentation, see original declaration: `Data.Comp.Multi.Generic.query` `O.query` query :: (O.All O.HFoldable fs, O.All O.HFunctor fs) => (forall i. Term fs i -> r) -> (r -> r -> r) -> Term fs l -> r query :: (forall i. Term fs i -> r) -> (r -> r -> r) -> Term fs l -> r query = (forall i. Term fs i -> r) -> (r -> r -> r) -> Term fs l -> r forall (f :: (* -> *) -> * -> *) r. HFoldable f => (HFix f :=> r) -> (r -> r -> r) -> HFix f :=> r O.query ---------------- Redefinitions for Cubix -------------------------------------------------- type MCSig = C.MCSig type MJavaSig = Java.MJavaSig type MJSSig = JS.MJSSig type MLuaSig = Lua.MLuaSig type MPythonSig = Python.MPythonSig