Skip to content
Snippets Groups Projects
Commit 983d355b authored by chrg's avatar chrg
Browse files

Work in progress

parent 0b6e390b
No related branches found
No related tags found
No related merge requests found
...@@ -25,3 +25,7 @@ cabal.project.local~ ...@@ -25,3 +25,7 @@ cabal.project.local~
.DS_Store .DS_Store
result result
a.out
rtree-c
test.c
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PackageImports #-}
import Control.RTree
import Data.Maybe (catMaybes, fromMaybe)
import Language.C qualified as C
import "pretty" Text.PrettyPrint qualified as P
import "transformers" Control.Monad.Trans.Maybe
import "typed-process" System.Process.Typed
main :: IO ()
main = do
C.parseCFilePre "test/data/file2.c" >>= \case
Right file -> do
l <- runMaybeT (reduce' check (reduceC file))
case l of
Just l' -> output l'
Nothing ->
putStrLn "Failure"
Left err ->
print err
where
output l = do
writeFile "test.c" (P.render (C.pretty l))
check l = MaybeT do
putStrLn "Outputting test"
output l
putStrLn "Running test"
err <- runProcess (proc "clang" ["-O0", "test.c"])
putStrLn $ "Done test" <> show err
pure $ if err == ExitSuccess then Just () else Nothing
type Lab = C.Ident
reduceC :: C.CTranslUnit -> RTree' Lab C.CTranslUnit
reduceC (C.CTranslUnit es _) = do
es' <- traverse rCExternalDeclaration es
pure $ C.CTranslUnit (catMaybes es') C.undefNode
rCExternalDeclaration
:: C.CExternalDeclaration C.NodeInfo
-> RTree' Lab (Maybe (C.CExternalDeclaration C.NodeInfo))
rCExternalDeclaration e = case e of
C.CFDefExt fun ->
split
(funName fun)
(pure Nothing)
(Just . C.CFDefExt <$> rCFunctionDef fun)
_ -> pure Nothing <| pure (Just e)
where
funName (C.CFunDef _ (C.CDeclr x _ _ _ _) _ _ _) =
x
rCFunctionDef :: C.CFunctionDef C.NodeInfo -> RTree' Lab (C.CFunctionDef C.NodeInfo)
rCFunctionDef (C.CFunDef spc dec cdecls smt _) = do
smt' <- rCStatement smt
pure $ C.CFunDef spc dec cdecls smt' C.undefNode
rCStatement :: C.CStatement C.NodeInfo -> RTree' Lab (C.CStatement C.NodeInfo)
rCStatement = \case
C.CCompound is cbi _ -> do
cbi' <- traverse rCCompoundBlockItem cbi
pure $ C.CCompound is (catMaybes cbi') C.undefNode
C.CExpr (Just e) _ -> do
e' <- rCExpression e
pure $ C.CExpr e' C.undefNode
a -> pure a
rCExpression :: C.CExpression C.NodeInfo -> RTree' Lab (Maybe (C.CExpression C.NodeInfo))
rCExpression = \case
C.CVar i _ ->
splitOn
i
(pure Nothing)
(pure . Just $ C.CVar i C.undefNode)
C.CCall e es _ -> do
me' <- rCExpression e
case me' of
Nothing -> pure Nothing
Just e' -> do
es' <-
traverse
( fmap
( fromMaybe (C.CConst (C.CIntConst (C.cInteger 0) C.undefNode))
)
. rCExpression
)
es
pure . Just $ C.CCall e' es' C.undefNode
e -> pure Nothing <| pure (Just e)
rCCompoundBlockItem :: C.CCompoundBlockItem C.NodeInfo -> RTree' Lab (Maybe (C.CCompoundBlockItem C.NodeInfo))
rCCompoundBlockItem a = pure Nothing <| pure (Just a)
...@@ -21,11 +21,11 @@ ...@@ -21,11 +21,11 @@
"language-c": { "language-c": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1664454938, "lastModified": 1701177364,
"narHash": "sha256-GDjXcq0oYNDGSIWO6kkIgF13RMwykDpUyAQAWRYEOUc=", "narHash": "sha256-SwRI8+PNfzfHOjFcn7bvgAylJeUMaFsvlJPm2r3QhTY=",
"owner": "kalhauge", "owner": "kalhauge",
"repo": "language-c", "repo": "language-c",
"rev": "0b2f7bf94789b09bbf1e7a1ab80b62f99e1e92f7", "rev": "bdbf9f641149f5879dc23eb9e153e573d9355cbd",
"type": "github" "type": "github"
}, },
"original": { "original": {
......
...@@ -2,21 +2,22 @@ ...@@ -2,21 +2,22 @@
inputs = { inputs = {
nixpkgs.url = github:nixos/nixpkgs/nixpkgs-unstable; nixpkgs.url = github:nixos/nixpkgs/nixpkgs-unstable;
flake-utils.url = github:numtide/flake-utils; flake-utils.url = github:numtide/flake-utils;
language-c = { url = github:kalhauge/language-c; flake = false; }; language-c = {
url = github:kalhauge/language-c;
flake = false;
}; };
outputs = };
{ self outputs = {
, nixpkgs self,
, flake-utils nixpkgs,
, ... flake-utils,
}@inputs: ...
let } @ inputs: let
packages = final: p: { packages = final: p: {
"rtree" = p.callCabal2nixWithOptions "rtree" "${self}" "" {}; "rtree" = p.callCabal2nixWithOptions "rtree" "${self}" "" {};
"language-c" = "language-c" =
final.haskell.lib.overrideCabal final.haskell.lib.overrideCabal
(p.callCabal2nixWithOptions "language-c" inputs.language-c "" { }) (p.callCabal2nixWithOptions "language-c" inputs.language-c "" {}) {
{
doCheck = false; doCheck = false;
}; };
}; };
...@@ -26,22 +27,21 @@ ...@@ -26,22 +27,21 @@
in in
{ {
overlays.default = overlays; overlays.default = overlays;
} // }
flake-utils.lib.eachDefaultSystem // flake-utils.lib.eachDefaultSystem
(system: (system: let
let hpkgs =
hpkgs = (import nixpkgs { (import nixpkgs {
inherit system; inherit system;
overlays = [overlays]; overlays = [overlays];
}).haskellPackages; })
in .haskellPackages;
rec { in rec {
packages = { packages = {
default = hpkgs.rtree; default = hpkgs.rtree;
rtree = hpkgs.rtree; rtree = hpkgs.rtree;
}; };
devShells = devShells = let
let
buildInputs = with hpkgs; [ buildInputs = with hpkgs; [
cabal-install cabal-install
ghcid ghcid
...@@ -50,13 +50,12 @@ ...@@ -50,13 +50,12 @@
fourmolu fourmolu
]; ];
withHoogle = true; withHoogle = true;
in in {
{ default =
default = hpkgs.shellFor hpkgs.shellFor
{ {
name = "rtree-shell"; name = "rtree-shell";
packages = p: packages = p: [p.rtree];
[ p.rtree ];
inherit buildInputs withHoogle; inherit buildInputs withHoogle;
}; };
}; };
......
...@@ -5,7 +5,7 @@ name: rtree ...@@ -5,7 +5,7 @@ name: rtree
# category: categories # category: categories
# extra-source-files: [] # extra-source-files: []
ghc-options: -Wall -fno-warn-incomplete-uni-patterns -Werror ghc-options: -Wall -fno-warn-incomplete-uni-patterns
dependencies: dependencies:
- base >= 4.9 && < 5 - base >= 4.9 && < 5
...@@ -13,11 +13,21 @@ dependencies: ...@@ -13,11 +13,21 @@ dependencies:
- free - free
- data-fix - data-fix
- mtl - mtl
- language-c - containers
library: library:
source-dirs: src source-dirs: src
executables:
rtree-c:
source-dirs: bin/rtree-c
main: Main.hs
dependencies:
- rtree
- language-c
- typed-process
- pretty
tests: tests:
rtree-test: rtree-test:
source-dirs: test/src source-dirs: test/src
......
...@@ -15,14 +15,34 @@ library ...@@ -15,14 +15,34 @@ library
Paths_rtree Paths_rtree
hs-source-dirs: hs-source-dirs:
src src
ghc-options: -Wall -fno-warn-incomplete-uni-patterns -Werror ghc-options: -Wall -fno-warn-incomplete-uni-patterns
build-depends: build-depends:
base >=4.9 && <5 base >=4.9 && <5
, containers
, data-fix
, free
, mtl
, transformers
default-language: Haskell2010
executable rtree-c
main-is: Main.hs
other-modules:
Paths_rtree
hs-source-dirs:
bin/rtree-c
ghc-options: -Wall -fno-warn-incomplete-uni-patterns
build-depends:
base >=4.9 && <5
, containers
, data-fix , data-fix
, free , free
, language-c , language-c
, mtl , mtl
, pretty
, rtree
, transformers , transformers
, typed-process
default-language: Haskell2010 default-language: Haskell2010
test-suite rtree-test test-suite rtree-test
...@@ -32,9 +52,10 @@ test-suite rtree-test ...@@ -32,9 +52,10 @@ test-suite rtree-test
Paths_rtree Paths_rtree
hs-source-dirs: hs-source-dirs:
test/src test/src
ghc-options: -Wall -fno-warn-incomplete-uni-patterns -Werror ghc-options: -Wall -fno-warn-incomplete-uni-patterns
build-depends: build-depends:
base >=4.9 && <5 base >=4.9 && <5
, containers
, data-fix , data-fix
, diagrams , diagrams
, diagrams-contrib , diagrams-contrib
...@@ -42,7 +63,6 @@ test-suite rtree-test ...@@ -42,7 +63,6 @@ test-suite rtree-test
, diagrams-lib , diagrams-lib
, diagrams-svg , diagrams-svg
, free , free
, language-c
, mtl , mtl
, rtree , rtree
, transformers , transformers
......
...@@ -2,11 +2,13 @@ ...@@ -2,11 +2,13 @@
{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DerivingVia #-} {-# LANGUAGE DerivingVia #-}
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-} {-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LambdaCase #-} {-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PackageImports #-} {-# LANGUAGE PackageImports #-}
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE ViewPatterns #-}
...@@ -16,61 +18,191 @@ Module: Control.RTree ...@@ -16,61 +18,191 @@ Module: Control.RTree
module Control.RTree where module Control.RTree where
import Control.Applicative (Alternative ((<|>))) import Control.Applicative (Alternative ((<|>)))
import Data.Functor import Data.Coerce (coerce)
import Data.Functor.Classes import Data.Functor.Classes
import qualified Data.List.NonEmpty as NE import qualified Data.List.NonEmpty as NE
import Data.Void
import Data.Coerce (coerce) import qualified Data.List as L
import "free" Control.Monad.Free
import Control.Monad.Reader
import "free" Control.Monad.Free.Church
-- | The reduction tree -- | The base functor for the reduction tree.
data RTreeF f data RTreeF l f
= f :<| f = Split (Maybe l) f f
| Lab String f f
deriving (Show, Eq, Functor) deriving (Show, Eq, Functor)
instance Show1 RTreeF where instance (Show l) => Show1 (RTreeF l) where
liftShowsPrec = undefined liftShowsPrec = undefined
newtype RTree i = RTree {rtreeFree :: Free RTreeF i} newtype RTree l i = RTree {rtreeFree :: F (RTreeF l) i}
deriving (Show) deriving (Functor, Applicative, Monad) via (F (RTreeF l))
deriving (Functor, Applicative, Monad) via (Free RTreeF)
instance MonadFree RTreeF RTree where instance MonadFree (RTreeF l) (RTree l) where
wrap x = RTree (Free (fmap rtreeFree x)) wrap x = RTree (wrap (fmap rtreeFree x))
infixr 3 <| infixr 3 <|
infixl 3 |> infixl 3 |>
(<|) :: (MonadFree RTreeF r) => r i -> r i -> r i {-# INLINE (<|) #-}
r1 <| r2 = wrap (r1 :<| r2) (<|) :: (MonadFree (RTreeF l) r) => r i -> r i -> r i
r1 <| r2 = wrap (Split Nothing r1 r2)
lab :: (MonadFree RTreeF r) => String -> r i -> r i -> r i {-# INLINE splitOn #-}
lab l r1 r2 = wrap (Lab l r1 r2) splitOn :: (MonadFree (RTreeF l) r) => l -> r i -> r i -> r i
splitOn l r1 r2 = wrap (Split (Just l) r1 r2)
(|>) :: (MonadFree RTreeF r) => r i -> r i -> r i {-# INLINE split #-}
r1 |> r2 = wrap (r2 :<| r1) split :: (MonadFree (RTreeF l) r) => Maybe l -> r i -> r i -> r i
split l r1 r2 = wrap (Split l r1 r2)
foldR :: (RTreeF a -> a) -> RTree a -> a {-# INLINE (|>) #-}
(|>) :: (MonadFree (RTreeF l) r) => r i -> r i -> r i
r1 |> r2 = r2 <| r1
{-# INLINE foldR #-}
foldR :: (RTreeF l a -> a) -> RTree l a -> a
foldR fn = coerce $ iter fn foldR fn = coerce $ iter fn
foldRM :: (Monad m) => (RTreeF l (m a) -> m a) -> RTree l a -> m a
foldRM fn = coerce $ iterM fn
-- | Extract the input from the reducer. -- | Extract the input from the reducer.
extract :: RTree i -> i extract :: RTree l i -> i
extract = foldR \case extract = foldR \(Split _ _ e) -> e
(_ :<| e) -> e
Lab _ _ e -> e -- | Remove all labels from a RTree by expanding all choices.
flatten :: forall i l. (Eq l) => RTree l i -> Maybe (RTree Void i)
flatten t = foldR go (fmap (const . Just . pure) t) []
where
go (Split ml lhs rhs) lst =
case ml of
Just l -> case l `L.lookup` lst of
Nothing -> do
join' (lhs $ (l, False) : lst) (rhs $ (l, True) : lst)
Just True ->
join' (lhs lst) (rhs lst)
Just False ->
Nothing
Nothing -> join' (lhs lst) (rhs lst)
join' mlhs mrhs = do
case (mlhs, mrhs) of
(Just lhs', Just rhs') -> pure (lhs' <| rhs')
_ -> mlhs <|> mrhs
-- | Reduce an input using a monad.
reduce
:: forall m i
. (Alternative m)
=> (i -> m ())
-> RTree Void i
-> m i
reduce p t = do
let (mi, i') = foldR go $ fmap (\i -> (pure i, i)) t
p i' *> mi
where
go :: RTreeF l (m i, i) -> (m i, i)
go (Split _ (lhs, le) (rhs, re)) =
((p le *> lhs) <|> rhs, re)
{-# INLINE reduce #-}
data RTree' l i
= RTree' (RTreeF l (RTree' l i))
| Done i
extract' :: RTree' l i -> i
extract' = \case
RTree' (Split _ _ v) -> extract' v
Done v -> v
instance Functor (RTree' l) where
fmap f (Done i) = Done (f i)
fmap f (RTree' r) = RTree' (fmap (fmap f) r)
instance Applicative (RTree' l) where
pure = Done
(<*>) = ap
instance Monad (RTree' l) where
ma >>= f = case ma of
Done i -> f i
RTree' r ->
RTree'
(fmap (>>= f) r)
instance MonadFree (RTreeF l) (RTree' l) where
wrap = RTree'
{-# INLINE wrap #-}
-- | Reduce an input using a monad. -- | Reduce an input using a monad.
reduce :: (Alternative m) => (i -> m ()) -> RTree i -> m i reduce'
reduce fn = :: forall m l i
( foldR \case . (Alternative m)
lhs :<| rhs -> lhs <|> rhs => (i -> m ())
Lab _ lhs rhs -> lhs <|> rhs -> RTree' l i
) -> m i
. fmap (\i -> fn i $> i) reduce' p = checkgo
where
go = \case
(Done i) -> pure i
(RTree' (Split _ lhs rhs)) ->
(checkgo lhs <|> go rhs)
checkgo rt = p (extract' rt) *> go rt
-- newtype I l i = I ([(l, Bool)] -> RTreeI l i)
--
-- data RTreeI l i
-- = RTreeI (RTreeF l (I l i))
-- | DoneI !i
-- -- This is not a great defintions, as the i does not depend on
-- -- the current i, but instead on the final I.
-- data RTreeIO j i = RTreeIO ((j -> IO Bool) -> IO i) j
--
-- extractIO :: RTreeIO j i -> j
-- extractIO (RTreeIO _ i) = i
-- instance Functor (RTreeIO j) where
-- fmap f (RTreeIO mf i) = RTreeIO (\h -> f <$> mf (h . f)) (f i)
--
-- instance Applicative (RTreeIO j) where
-- pure i = RTreeIO (\_ -> pure i) i
-- (<*>) = ap
--
-- -- RTreeIO f fi <*> RTreeIO a ai = RTreeIO (f <*> a) (fi ai)
--
-- instance Monad (RTreeIO j) where
-- RTreeIO (ma :: ((a -> IO Bool) -> IO a)) a >>= (f :: (a -> RTreeIO b)) =
-- RTreeIO undefined (extractIO $ f a)
--
-- instance MonadFree (RTreeF Void) (RTreeIO j) where
-- wrap (Split Nothing (RTreeIO lhs le) (RTreeIO rhs re)) =
-- RTreeIO
-- ( \p ->
-- p le >>= \case
-- True -> lhs p
-- False -> rhs p
-- )
-- re
-- wrap (Split (Just x) _ _) = absurd x
-- reduceIO
-- :: forall i
-- . (i -> IO Bool)
-- -> RTreeIO j i
-- -> IO (Maybe i)
-- reduceIO p (RTreeIO rt i) = runMaybeT do
-- let (mi, i') = foldR go $ fmap (\i -> (pure i, i)) t
-- p i' *> mi
-- where
-- go :: RTreeF l (IO i, i) -> (IO i, i)
-- go (Split _ (lhs, le) (rhs, re)) =
-- ((p le *> lhs) <|> rhs, re)
-- | Split the world on a fact. False it does not happen, and True it does happen. -- | Split the world on a fact. False it does not happen, and True it does happen.
given :: RTree Bool given :: RTree Void Bool
given = pure False <| pure True given = pure False <| pure True
{- | A reducer should extract itself {- | A reducer should extract itself
...@@ -78,11 +210,11 @@ given = pure False <| pure True ...@@ -78,11 +210,11 @@ given = pure False <| pure True
extract . red = id extract . red = id
@ @
-} -}
lawReduceId :: (Eq i) => (i -> RTree i) -> i -> Bool lawReduceId :: (Eq i) => (i -> RTree l i) -> i -> Bool
lawReduceId red i = extract (red i) == i lawReduceId red i = extract (red i) == i
-- | Reducing a list one element at a time. -- | Reducing a list one element at a time.
rList :: [a] -> RTree [a] rList :: [a] -> RTree l [a]
rList = \case rList = \case
[] -> pure [] [] -> pure []
a : as -> rList as <| (a :) <$> rList as a : as -> rList as <| (a :) <$> rList as
...@@ -90,7 +222,7 @@ rList = \case ...@@ -90,7 +222,7 @@ rList = \case
{- | Binary reduction on the list assumming suffixes all contain eachother: {- | Binary reduction on the list assumming suffixes all contain eachother:
@[] < [c] < [b, c] < [a,b,c]@ @[] < [c] < [b, c] < [a,b,c]@
-} -}
rSuffixList :: [a] -> RTree [a] rSuffixList :: [a] -> RTree l [a]
rSuffixList as = do rSuffixList as = do
res <- exponentialSearch (NE.tails as) res <- exponentialSearch (NE.tails as)
case res of case res of
...@@ -100,7 +232,7 @@ rSuffixList as = do ...@@ -100,7 +232,7 @@ rSuffixList as = do
{- | Given a progression of inputs that are progressively larger, pick the smallest using {- | Given a progression of inputs that are progressively larger, pick the smallest using
binary search. binary search.
-} -}
binarySearch :: NE.NonEmpty i -> RTree i binarySearch :: NE.NonEmpty i -> RTree l i
binarySearch = \case binarySearch = \case
a NE.:| [] -> pure a a NE.:| [] -> pure a
d -> binarySearch l <| binarySearch f d -> binarySearch l <| binarySearch f
...@@ -110,7 +242,7 @@ binarySearch = \case ...@@ -110,7 +242,7 @@ binarySearch = \case
{- | Given a progression of inputs that are progressively larger, pick the smallest using {- | Given a progression of inputs that are progressively larger, pick the smallest using
binary search. binary search.
-} -}
exponentialSearch :: NE.NonEmpty i -> RTree i exponentialSearch :: NE.NonEmpty i -> RTree l i
exponentialSearch = go 1 exponentialSearch = go 1
where where
go n = \case go n = \case
...@@ -126,15 +258,15 @@ nonEmptyOr msg ls = case NE.nonEmpty ls of ...@@ -126,15 +258,15 @@ nonEmptyOr msg ls = case NE.nonEmpty ls of
Nothing -> error msg Nothing -> error msg
-- | Given a list of orderd options, the -- | Given a list of orderd options, the
linearSearch :: NE.NonEmpty i -> RTree i linearSearch :: NE.NonEmpty i -> RTree l i
linearSearch = foldr1 (<|) . fmap pure linearSearch = foldr1 (<|) . fmap pure
-- | Given a list of orderd options, the -- | Given a list of orderd options, the
linearSearch' :: [i] -> RTree (Maybe i) linearSearch' :: [i] -> RTree l (Maybe i)
linearSearch' is = linearSearch (NE.fromList $ fmap Just is ++ [Nothing]) linearSearch' is = linearSearch (NE.fromList $ fmap Just is ++ [Nothing])
-- | Given -- | Given
ddmin :: [i] -> RTree [i] ddmin :: [i] -> RTree l [i]
ddmin = \case ddmin = \case
[] -> pure [] [] -> pure []
[a] -> pure [a] [a] -> pure [a]
......
file2.c
extern int printf (const char *, ...);
int main (void)
{
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment