diff --git a/semantic-core/semantic-core.cabal b/semantic-core/semantic-core.cabal index 28fd58fd0f..ba80c082eb 100644 --- a/semantic-core/semantic-core.cabal +++ b/semantic-core/semantic-core.cabal @@ -84,6 +84,7 @@ test-suite spec other-modules: Generators build-depends: base , semantic-core + , fused-effects , hedgehog ^>= 1 , tasty >= 1.2 && <2 , tasty-hedgehog ^>= 1.0.0.1 diff --git a/semantic-core/src/Analysis/Concrete.hs b/semantic-core/src/Analysis/Concrete.hs index 7ae7801714..f1db97213c 100644 --- a/semantic-core/src/Analysis/Concrete.hs +++ b/semantic-core/src/Analysis/Concrete.hs @@ -42,7 +42,7 @@ newtype FrameId = FrameId { unFrameId :: Precise } deriving (Eq, Ord, Show) data Concrete - = Closure Loc User (Term Core.Core User) Env + = Closure Loc User (Term (Core.Ann :+: Core.Core) User) Env | Unit | Bool Bool | String Text @@ -70,7 +70,7 @@ data Edge = Lexical | Import -- -- >>> map fileBody (snd (concrete [File (Loc "bool" emptySpan) (Core.bool True)])) -- [Right (Bool True)] -concrete :: [File (Term Core.Core User)] -> (Heap, [File (Either (Loc, String) Concrete)]) +concrete :: [File (Term (Core.Ann :+: Core.Core) User)] -> (Heap, [File (Either (Loc, String) Concrete)]) concrete = run . runFresh @@ -82,7 +82,7 @@ runFile :: ( Carrier sig m , Member Fresh sig , Member (State Heap) sig ) - => File (Term Core.Core User) + => File (Term (Core.Ann :+: Core.Core) User) -> m (File (Either (Loc, String) Concrete)) runFile file = traverse run file where run = runReader (fileLoc file) diff --git a/semantic-core/src/Analysis/Eval.hs b/semantic-core/src/Analysis/Eval.hs index 15abe28087..1080a740db 100644 --- a/semantic-core/src/Analysis/Eval.hs +++ b/semantic-core/src/Analysis/Eval.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE FlexibleContexts, LambdaCase, OverloadedStrings, RankNTypes, RecordWildCards #-} +{-# LANGUAGE FlexibleContexts, LambdaCase, OverloadedStrings, RankNTypes, RecordWildCards, TypeOperators #-} module Analysis.Eval ( eval , prog1 @@ -12,6 +12,7 @@ module Analysis.Eval ) where import Control.Applicative (Alternative (..)) +import Control.Effect.Carrier import Control.Effect.Fail import Control.Effect.Reader import Control.Monad ((>=>)) @@ -33,11 +34,11 @@ eval :: ( Carrier sig m , Semigroup value ) => Analysis address value m - -> (Term Core User -> m value) - -> (Term Core User -> m value) + -> (Term (Ann :+: Core) User -> m value) + -> (Term (Ann :+: Core) User -> m value) eval Analysis{..} eval = \case Var n -> lookupEnv' n >>= deref' n - Term c -> case c of + Term (R c) -> case c of Rec (Named (Ignored n) b) -> do addr <- alloc n v <- bind n addr (eval (instantiate1 (pure n) b)) @@ -71,7 +72,7 @@ eval Analysis{..} eval = \case b' <- eval b addr <- ref a b' <$ assign addr b' - Ann loc c -> local (const loc) (eval c) + Term (L (Ann loc c)) -> local (const loc) (eval c) where freeVariable s = fail ("free variable: " <> s) uninitialized s = fail ("uninitialized variable: " <> s) invalidRef s = fail ("invalid ref: " <> s) @@ -81,41 +82,41 @@ eval Analysis{..} eval = \case ref = \case Var n -> lookupEnv' n - Term c -> case c of + Term (R c) -> case c of If c t e -> do c' <- eval c >>= asBool if c' then ref t else ref e a :. b -> do a' <- ref a a' ... b >>= maybe (freeVariable (show b)) pure - Ann loc c -> local (const loc) (ref c) c -> invalidRef (show c) + Term (L (Ann loc c)) -> local (const loc) (ref c) -prog1 :: File (Term Core User) +prog1 :: (Carrier sig t, Member Core sig) => File (t User) prog1 = fromBody $ lam (named' "foo") ( named' "bar" :<- pure "foo" >>>= Core.if' (pure "bar") (Core.bool False) (Core.bool True)) -prog2 :: File (Term Core User) +prog2 :: (Carrier sig t, Member Core sig) => File (t User) prog2 = fromBody $ fileBody prog1 $$ Core.bool True -prog3 :: File (Term Core User) +prog3 :: (Carrier sig t, Member Core sig) => File (t User) prog3 = fromBody $ lams [named' "foo", named' "bar", named' "quux"] (Core.if' (pure "quux") (pure "bar") (pure "foo")) -prog4 :: File (Term Core User) +prog4 :: (Carrier sig t, Member Core sig) => File (t User) prog4 = fromBody ( named' "foo" :<- Core.bool True >>>= Core.if' (pure "foo") (Core.bool True) (Core.bool False)) -prog5 :: File (Term Core User) +prog5 :: (Carrier sig t, Member Ann sig, Member Core sig) => File (t User) prog5 = fromBody $ ann (do' [ Just (named' "mkPoint") :<- lams [named' "_x", named' "_y"] (ann (Core.record [ ("x", ann (pure "_x")) @@ -126,7 +127,7 @@ prog5 = fromBody $ ann (do' , Nothing :<- ann (ann (pure "point") Core.... "y") .= ann (ann (pure "point") Core.... "x") ]) -prog6 :: [File (Term Core User)] +prog6 :: (Carrier sig t, Member Core sig) => [File (t User)] prog6 = [ File (Loc "dep" (locSpan (fromJust here))) $ Core.record [ ("dep", Core.record [ ("var", Core.bool True) ]) ] @@ -136,7 +137,7 @@ prog6 = ]) ] -ruby :: File (Term Core User) +ruby :: (Carrier sig t, Member Ann sig, Member Core sig) => File (t User) ruby = fromBody $ annWith callStack (rec (named' __semantic_global) (do' statements)) where statements = [ Just "Class" :<- record @@ -219,8 +220,8 @@ data Analysis address value m = Analysis , lookupEnv :: User -> m (Maybe address) , deref :: address -> m (Maybe value) , assign :: address -> value -> m () - , abstract :: (Term Core User -> m value) -> User -> Term Core User -> m value - , apply :: (Term Core User -> m value) -> value -> value -> m value + , abstract :: (Term (Ann :+: Core) User -> m value) -> User -> Term (Ann :+: Core) User -> m value + , apply :: (Term (Ann :+: Core) User -> m value) -> value -> value -> m value , unit :: m value , bool :: Bool -> m value , asBool :: value -> m Bool diff --git a/semantic-core/src/Analysis/FlowInsensitive.hs b/semantic-core/src/Analysis/FlowInsensitive.hs index ca23d01e8f..fdf0cc7fa4 100644 --- a/semantic-core/src/Analysis/FlowInsensitive.hs +++ b/semantic-core/src/Analysis/FlowInsensitive.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE FlexibleContexts, OverloadedStrings, ScopedTypeVariables #-} +{-# LANGUAGE FlexibleContexts, OverloadedStrings, ScopedTypeVariables, TypeOperators #-} module Analysis.FlowInsensitive ( Heap , FrameId(..) @@ -20,7 +20,7 @@ import Data.Monoid (Alt(..)) import qualified Data.Set as Set import Data.Term (Term) -type Cache name a = Map.Map (Term Core.Core name) (Set.Set a) +type Cache name a = Map.Map (Term (Core.Ann :+: Core.Core) name) (Set.Set a) type Heap name a = Map.Map name (Set.Set a) newtype FrameId name = FrameId { unFrameId :: name } @@ -35,8 +35,8 @@ convergeTerm :: forall m sig a name , Ord a , Ord name ) - => (Term Core.Core name -> NonDetC (ReaderC (Cache name a) (StateC (Cache name a) m)) a) - -> Term Core.Core name + => (Term (Core.Ann :+: Core.Core) name -> NonDetC (ReaderC (Cache name a) (StateC (Cache name a) m)) a) + -> Term (Core.Ann :+: Core.Core) name -> m (Set.Set a) convergeTerm eval body = do heap <- get @@ -53,8 +53,8 @@ cacheTerm :: forall m sig a name , Ord a , Ord name ) - => (Term Core.Core name -> m a) - -> (Term Core.Core name -> m a) + => (Term (Core.Ann :+: Core.Core) name -> m a) + -> (Term (Core.Ann :+: Core.Core) name -> m a) cacheTerm eval term = do cached <- gets (Map.lookup term) case cached :: Maybe (Set.Set a) of diff --git a/semantic-core/src/Analysis/ImportGraph.hs b/semantic-core/src/Analysis/ImportGraph.hs index 5e87e38ec1..f5b8a8d827 100644 --- a/semantic-core/src/Analysis/ImportGraph.hs +++ b/semantic-core/src/Analysis/ImportGraph.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE FlexibleContexts, OverloadedStrings, RecordWildCards #-} +{-# LANGUAGE FlexibleContexts, OverloadedStrings, RecordWildCards, TypeOperators #-} module Analysis.ImportGraph ( ImportGraph , importGraph @@ -41,14 +41,14 @@ instance Monoid Value where mempty = Value Abstract mempty data Semi - = Closure Loc User (Term Core.Core User) User + = Closure Loc User (Term (Core.Ann :+: Core.Core) User) User -- FIXME: Bound String values. | String Text | Abstract deriving (Eq, Ord, Show) -importGraph :: [File (Term Core.Core User)] -> (Heap User Value, [File (Either (Loc, String) Value)]) +importGraph :: [File (Term (Core.Ann :+: Core.Core) User)] -> (Heap User Value, [File (Either (Loc, String) Value)]) importGraph = run . runFresh @@ -61,7 +61,7 @@ runFile :: ( Carrier sig m , Member (Reader (FrameId User)) sig , Member (State (Heap User Value)) sig ) - => File (Term Core.Core User) + => File (Term (Core.Ann :+: Core.Core) User) -> m (File (Either (Loc, String) Value)) runFile file = traverse run file where run = runReader (fileLoc file) diff --git a/semantic-core/src/Analysis/Typecheck.hs b/semantic-core/src/Analysis/Typecheck.hs index 916b21559f..25d9268e1a 100644 --- a/semantic-core/src/Analysis/Typecheck.hs +++ b/semantic-core/src/Analysis/Typecheck.hs @@ -88,7 +88,7 @@ generalize :: Term Monotype Meta -> Term (Polytype :+: Monotype) Void generalize ty = fromJust (closed (forAlls (IntSet.toList (mvs ty)) (hoistTerm R ty))) -typecheckingFlowInsensitive :: [File (Term Core.Core User)] -> (Heap User (Term Monotype Meta), [File (Either (Loc, String) (Term (Polytype :+: Monotype) Void))]) +typecheckingFlowInsensitive :: [File (Term (Core.Ann :+: Core.Core) User)] -> (Heap User (Term Monotype Meta), [File (Either (Loc, String) (Term (Polytype :+: Monotype) Void))]) typecheckingFlowInsensitive = run . runFresh @@ -101,7 +101,7 @@ runFile :: ( Carrier sig m , Member Fresh sig , Member (State (Heap User (Term Monotype Meta))) sig ) - => File (Term Core.Core User) + => File (Term (Core.Ann :+: Core.Core) User) -> m (File (Either (Loc, String) (Term Monotype Meta))) runFile file = traverse run file where run diff --git a/semantic-core/src/Data/Core.hs b/semantic-core/src/Data/Core.hs index 65bbbe7ba6..dbac3a782d 100644 --- a/semantic-core/src/Data/Core.hs +++ b/semantic-core/src/Data/Core.hs @@ -27,6 +27,7 @@ module Data.Core , record , (...) , (.=) +, Ann(..) , ann , annWith , instantiate @@ -75,7 +76,6 @@ data Core f a | f a :. User -- | Assignment of a value to the reference returned by the lhs. | f a := f a - | Ann Loc (f a) deriving (Foldable, Functor, Generic1, Traversable) infixr 1 :>> @@ -105,7 +105,6 @@ instance RightModule Core where Record fs >>=* f = Record (map (fmap (>>= f)) fs) (a :. b) >>=* f = (a >>= f) :. b (a := b) >>=* f = (a >>= f) := (b >>= f) - Ann l b >>=* f = Ann l (b >>= f) rec :: (Eq a, Carrier sig m, Member Core sig) => Named a -> m a -> m a @@ -212,15 +211,25 @@ a .= b = send (a := b) infix 3 .= -ann :: (Carrier sig m, Member Core sig) => HasCallStack => m a -> m a + +data Ann f a + = Ann Loc (f a) + deriving (Eq, Foldable, Functor, Generic1, Ord, Show, Traversable) + +instance HFunctor Ann + +instance RightModule Ann where + Ann l b >>=* f = Ann l (b >>= f) + + +ann :: (Carrier sig m, Member Ann sig) => HasCallStack => m a -> m a ann = annWith callStack -annWith :: (Carrier sig m, Member Core sig) => CallStack -> m a -> m a +annWith :: (Carrier sig m, Member Ann sig) => CallStack -> m a -> m a annWith callStack = maybe id (fmap send . Ann) (stackLoc callStack) -stripAnnotations :: (Member Core sig, HFunctor sig, forall g . Functor g => Functor (sig g)) => Term sig a -> Term sig a -stripAnnotations (Var v) = Var v -stripAnnotations (Term t) - | Just c <- prj t, Ann _ b <- c = stripAnnotations b - | otherwise = Term (hmap stripAnnotations t) +stripAnnotations :: (HFunctor sig, forall g . Functor g => Functor (sig g)) => Term (Ann :+: sig) a -> Term sig a +stripAnnotations (Var v) = Var v +stripAnnotations (Term (L (Ann _ b))) = stripAnnotations b +stripAnnotations (Term (R b)) = Term (hmap stripAnnotations b) diff --git a/semantic-core/src/Data/Core/Parser.hs b/semantic-core/src/Data/Core/Parser.hs index 3ae921dd75..25eff58a7d 100644 --- a/semantic-core/src/Data/Core/Parser.hs +++ b/semantic-core/src/Data/Core/Parser.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE FlexibleContexts, TypeOperators #-} module Data.Core.Parser ( module Text.Trifecta , core @@ -10,13 +10,13 @@ module Data.Core.Parser -- Consult @doc/grammar.md@ for an EBNF grammar. import Control.Applicative +import Control.Effect.Carrier import qualified Data.Char as Char import Data.Core ((:<-) (..), Core) import qualified Data.Core as Core import Data.Foldable (foldl') import Data.Name import Data.String -import Data.Term import qualified Text.Parser.Token as Token import qualified Text.Parser.Token.Highlight as Highlight import Text.Trifecta hiding (ident) @@ -46,23 +46,23 @@ identifier = choice [quote, plain] "identifier" where -- * Parsers (corresponding to EBNF) -core :: (TokenParsing m, Monad m) => m (Term Core User) +core :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t User) core = expr -expr :: (TokenParsing m, Monad m) => m (Term Core User) +expr :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t User) expr = ifthenelse <|> lambda <|> rec <|> load <|> assign -assign :: (TokenParsing m, Monad m) => m (Term Core User) +assign :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t User) assign = application <**> (symbolic '=' *> rhs <|> pure id) "assignment" where rhs = flip (Core..=) <$> application -application :: (TokenParsing m, Monad m) => m (Term Core User) +application :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t User) application = projection `chainl1` (pure (Core.$$)) -projection :: (TokenParsing m, Monad m) => m (Term Core User) +projection :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t User) projection = foldl' (Core....) <$> atom <*> many (namedValue <$ dot <*> name) -atom :: (TokenParsing m, Monad m) => m (Term Core User) +atom :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t User) atom = choice [ comp , lit @@ -70,29 +70,29 @@ atom = choice , parens expr ] -comp :: (TokenParsing m, Monad m) => m (Term Core User) +comp :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t User) comp = braces (Core.do' <$> sepEndByNonEmpty statement semi) "compound statement" -statement :: (TokenParsing m, Monad m) => m (Maybe (Named User) :<- Term Core User) +statement :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (Maybe (Named User) :<- t User) statement = try ((:<-) . Just <$> name <* symbol "<-" <*> expr) <|> (Nothing :<-) <$> expr "statement" -ifthenelse :: (TokenParsing m, Monad m) => m (Term Core User) +ifthenelse :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t User) ifthenelse = Core.if' <$ reserved "if" <*> expr <* reserved "then" <*> expr <* reserved "else" <*> expr "if-then-else statement" -rec :: (TokenParsing m, Monad m) => m (Term Core User) +rec :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t User) rec = Core.rec <$ reserved "rec" <*> name <* symbolic '=' <*> expr "recursive binding" -load :: (TokenParsing m, Monad m) => m (Term Core User) +load :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t User) load = Core.load <$ reserved "load" <*> expr -lvalue :: (TokenParsing m, Monad m) => m (Term Core User) +lvalue :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t User) lvalue = choice [ projection , ident @@ -104,7 +104,7 @@ lvalue = choice name :: (TokenParsing m, Monad m) => m (Named User) name = named' <$> identifier "name" -lit :: (TokenParsing m, Monad m) => m (Term Core User) +lit :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t User) lit = let x `given` n = x <$ reserved n in choice [ Core.bool True `given` "#true" , Core.bool False `given` "#false" @@ -113,13 +113,13 @@ lit = let x `given` n = x <$ reserved n in choice , Core.string <$> stringLiteral ] "literal" -record :: (TokenParsing m, Monad m) => m (Term Core User) +record :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t User) record = Core.record <$ reserved "#record" <*> braces (sepEndBy ((,) <$> identifier <* symbolic ':' <*> expr) comma) -lambda :: (TokenParsing m, Monad m) => m (Term Core User) +lambda :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t User) lambda = Core.lam <$ lambduh <*> name <* arrow <*> expr "lambda" where lambduh = symbolic 'λ' <|> symbolic '\\' arrow = symbol "→" <|> symbol "->" -ident :: (Monad m, TokenParsing m) => m (Term Core User) +ident :: (Applicative t, Monad m, TokenParsing m) => m (t User) ident = pure . namedValue <$> name "identifier" diff --git a/semantic-core/src/Data/Core/Pretty.hs b/semantic-core/src/Data/Core/Pretty.hs index 2bb0170b6b..d902402120 100644 --- a/semantic-core/src/Data/Core/Pretty.hs +++ b/semantic-core/src/Data/Core/Pretty.hs @@ -79,8 +79,6 @@ prettyCore style = precBody . go . fmap name , symbol "=" <+> align (withPrec 4 (go rhs)) ] - -- Annotations are not pretty-printed, as it lowers the signal/noise ratio too profoundly. - Ann _ c -> go c statement -> let (bindings, return) = unstatements (Term statement) statements = toList (bindings :> (Nothing :<- return)) diff --git a/semantic-core/test/Generators.hs b/semantic-core/test/Generators.hs index 3ec79e8bef..cab1ee0983 100644 --- a/semantic-core/test/Generators.hs +++ b/semantic-core/test/Generators.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE FlexibleContexts, ScopedTypeVariables #-} module Generators ( literal @@ -18,6 +18,7 @@ import Hedgehog hiding (Var) import qualified Hedgehog.Gen as Gen import qualified Hedgehog.Range as Range +import Control.Effect.Carrier import qualified Data.Core as Core import Data.Name import Data.Term @@ -29,16 +30,16 @@ name :: MonadGen m => m (Named User) name = Gen.prune (named' <$> names) where names = Gen.text (Range.linear 1 10) Gen.lower -boolean :: MonadGen m => m (Term Core.Core User) +boolean :: (Carrier sig t, Member Core.Core sig, MonadGen m) => m (t User) boolean = Core.bool <$> Gen.bool -variable :: MonadGen m => m (Term Core.Core User) +variable :: (Carrier sig t, Member Core.Core sig, MonadGen m) => m (t User) variable = pure . namedValue <$> name -ifthenelse :: MonadGen m => m (Term Core.Core User) -> m (Term Core.Core User) +ifthenelse :: (Carrier sig t, Member Core.Core sig, MonadGen m) => m (t User) -> m (t User) ifthenelse bod = Gen.subterm3 boolean bod bod Core.if' -apply :: MonadGen m => m (Term Core.Core User) -> m (Term Core.Core User) +apply :: (Carrier sig t, Member Core.Core sig, MonadGen m) => m (t User) -> m (t User) apply gen = go where go = Gen.recursive Gen.choice @@ -47,21 +48,21 @@ apply gen = go where , Gen.subtermM go (\x -> Core.lam <$> name <*> pure x) ] -lambda :: MonadGen m => m (Term Core.Core User) -> m (Term Core.Core User) +lambda :: (Carrier sig t, Member Core.Core sig, MonadGen m) => m (t User) -> m (t User) lambda bod = do arg <- name Gen.subterm bod (Core.lam arg) -record :: MonadGen m => m (Term Core.Core User) -> m (Term Core.Core User) +record :: (Carrier sig t, Member Core.Core sig, MonadGen m) => m (t User) -> m (t User) record bod = Core.record <$> Gen.list (Range.linear 0 5) ((,) . namedValue <$> name <*> bod) -atoms :: MonadGen m => [m (Term Core.Core User)] +atoms :: (Carrier sig t, Member Core.Core sig, MonadGen m) => [m (t User)] atoms = [variable, pure Core.unit, boolean, Core.string <$> Gen.text (Range.linear 1 10) Gen.lower] -literal :: MonadGen m => m (Term Core.Core User) +literal :: (Carrier sig t, Member Core.Core sig, MonadGen m) => m (t User) literal = Gen.recursive Gen.choice atoms [lambda literal, record literal] -expr :: MonadGen m => m (Term Core.Core User) +expr :: (Carrier sig t, Member Core.Core sig, MonadGen m) => m (t User) expr = Gen.recursive Gen.choice atoms [ Gen.subtermM expr (\x -> flip Core.rec x <$> name) , Gen.subterm2 expr expr (Core.>>>) diff --git a/semantic-core/test/Spec.hs b/semantic-core/test/Spec.hs index b877a4a1ef..85021bcb4a 100644 --- a/semantic-core/test/Spec.hs +++ b/semantic-core/test/Spec.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE OverloadedStrings, TypeOperators #-} module Main (main) where import Data.String @@ -9,6 +9,7 @@ import Test.Tasty import Test.Tasty.Hedgehog import Test.Tasty.HUnit +import Control.Effect.Sum import Data.File import qualified Generators as Gen import qualified Analysis.Eval as Eval @@ -20,7 +21,7 @@ import Data.Term -- * Helpers -true, false :: Term Core User +true, false :: Term (Ann :+: Core) User true = bool True false = bool False @@ -30,10 +31,10 @@ parseEither p = Trifecta.foldResult (Left . show . Trifecta._errDoc) Right . Tri -- * Parser roundtripping properties. Note that parsing and prettyprinting is generally -- not a roundtrip, because the parser inserts 'Ann' nodes itself. -prop_roundtrips :: Gen (Term Core User) -> Property +prop_roundtrips :: Gen (Term (Ann :+: Core) User) -> Property prop_roundtrips gen = property $ do input <- forAll gen - tripping input showCore (parseEither (Parse.core <* Trifecta.eof)) + tripping input (showCore . stripAnnotations) (parseEither (Parse.core <* Trifecta.eof)) parserProps :: TestTree parserProps = testGroup "Parsing: roundtripping" @@ -46,7 +47,7 @@ parserProps = testGroup "Parsing: roundtripping" -- * Parser specs -parsesInto :: String -> Term Core User -> Assertion +parsesInto :: String -> Term (Ann :+: Core) User -> Assertion parsesInto str res = case parseEither Parse.core str of Right x -> x @?= res Left m -> assertFailure m @@ -56,7 +57,7 @@ assert_booleans_parse = do parseEither Parse.core "#true" @?= Right true parseEither Parse.core "#false" @?= Right false -a, f, g, h :: Term Core User +a, f, g, h :: Term (Ann :+: Core) User (a, f, g, h) = (pure "a", pure "f", pure "g", pure "h") assert_ifthen_parse :: Assertion @@ -92,9 +93,9 @@ parserSpecs = testGroup "Parsing: simple specs" , testCase "quoted names" assert_quoted_name_parse ] -assert_roundtrips :: File (Term Core User) -> Assertion -assert_roundtrips (File _ core) = case parseEither Parse.core (showCore core) of - Right v -> v @?= stripAnnotations core +assert_roundtrips :: File (Term (Ann :+: Core) User) -> Assertion +assert_roundtrips (File _ core) = case parseEither Parse.core (showCore (stripAnnotations core)) of + Right v -> stripAnnotations v @?= stripAnnotations core Left e -> assertFailure e parserExamples :: TestTree