Skip to content

Commit 985c15c

Browse files
committed
Initial commit, everything up to code generation seems to work
0 parents  commit 985c15c

File tree

6 files changed

+214
-0
lines changed

6 files changed

+214
-0
lines changed

.gitignore

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
dist
2+
cabal-dev
3+
*.o
4+
*.hi
5+
*.chi
6+
*.chs.h
7+
.virtualenv
8+
.hsenv
9+
.cabal-sandbox/
10+
cabal.sandbox.config
11+
cabal.config

LICENSE

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright (c) 2015 Danny Gratzer
2+
3+
Permission is hereby granted, free of charge, to any person obtaining
4+
a copy of this software and associated documentation files (the
5+
"Software"), to deal in the Software without restriction, including
6+
without limitation the rights to use, copy, modify, merge, publish,
7+
distribute, sublicense, and/or sell copies of the Software, and to
8+
permit persons to whom the Software is furnished to do so, subject to
9+
the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included
12+
in all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Pcf.hs

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
2+
{-# LANGUAGE LambdaCase #-}
3+
module Pcf where
4+
import Bound
5+
import Control.Applicative
6+
import Control.Monad
7+
import Control.Monad.Gen
8+
import Control.Monad.Trans
9+
import Data.Foldable
10+
import Data.List (elemIndex)
11+
import qualified Data.Map as M
12+
import Data.Maybe (fromJust)
13+
import qualified Data.Set as S
14+
import Data.Traversable hiding (mapM)
15+
import Data.Void
16+
import Prelude.Extras
17+
18+
data Ty = Arr Ty Ty
19+
| Nat
20+
deriving Eq
21+
22+
data Exp a = V a
23+
| App (Exp a) (Exp a)
24+
| Lam Ty (Scope () Exp a)
25+
| Fix Ty (Scope () Exp a)
26+
| Suc (Exp a)
27+
| Zero
28+
deriving (Eq, Functor, Foldable, Traversable)
29+
30+
instance Eq1 Exp where
31+
instance Applicative Exp where
32+
pure = return
33+
(<*>) = ap
34+
instance Monad Exp where
35+
return = V
36+
V a >>= f = f a
37+
App l r >>= f = App (l >>= f) (r >>= f)
38+
Lam t body >>= f = Lam t (body >>>= f)
39+
Fix t body >>= f = Fix t (body >>>= f)
40+
Suc e >>= f = Suc (e >>= f)
41+
Zero >>= _ = Zero
42+
43+
{- Type checking 'n stuff -}
44+
type TyM a = GenT a Maybe
45+
46+
assertTy :: (Enum a, Ord a) => M.Map a Ty -> Exp a -> Ty -> TyM a ()
47+
assertTy env e t = (== t) <$> typeCheck env e >>= guard
48+
49+
typeCheck :: (Enum a, Ord a) => M.Map a Ty -> Exp a -> TyM a Ty
50+
typeCheck env Zero = return Nat
51+
typeCheck env (Suc e) = assertTy env e Nat >> return Nat
52+
typeCheck env (V a) = lift (M.lookup a env)
53+
typeCheck env (App f a) = typeCheck env f >>= \case
54+
Arr fTy tTy -> assertTy env a fTy >> return tTy
55+
_ -> mzero
56+
typeCheck env (Lam t bind) = do
57+
v <- gen
58+
Arr t <$> typeCheck (M.insert v t env) (instantiate1 (V v) bind)
59+
typeCheck env (Fix t bind) = do
60+
v <- gen
61+
assertTy (M.insert v t env) (instantiate1 (V v) bind) t
62+
return t
63+
64+
typeOf :: Exp Void -> Maybe Ty
65+
typeOf = runGenT . typeCheck M.empty . fmap (absurd :: Void -> Integer)
66+
67+
-- Invariant, Clos only contains VCs, can't be enforced statically due
68+
-- to annoying monad instance
69+
type Clos a = [ExpC a]
70+
71+
{- Closure Conversion -}
72+
data ExpC a = VC a
73+
| AppC (ExpC a) (ExpC a)
74+
| LamC Ty (Clos a) (Scope Int ExpC a)
75+
| FixC Ty (Clos a) (Scope Int ExpC a)
76+
| SucC (ExpC a)
77+
| ZeroC
78+
deriving (Eq, Functor, Foldable, Traversable)
79+
80+
instance Eq1 ExpC where
81+
instance Applicative ExpC where
82+
pure = return
83+
(<*>) = ap
84+
instance Monad ExpC where
85+
return = VC
86+
VC a >>= f = f a
87+
AppC l r >>= f = AppC (l >>= f) (r >>= f)
88+
LamC t clos body >>= f = LamC t (map (>>= f) clos) (body >>>= f)
89+
FixC t clos body >>= f = FixC t (map (>>= f) clos) (body >>>= f)
90+
SucC e >>= f = SucC (e >>= f)
91+
ZeroC >>= _ = ZeroC
92+
93+
closConv :: (Eq a, Ord a, Enum a) => Exp a -> Gen a (ExpC a)
94+
closConv (V a) = return (VC a)
95+
closConv Zero = return ZeroC
96+
closConv (Suc e) = SucC <$> closConv e
97+
closConv (App f a) = AppC <$> closConv f <*> closConv a
98+
closConv (Fix t bind) = do
99+
v <- gen
100+
body <- closConv (instantiate1 (V v) bind)
101+
let freeVars = S.toList . S.delete v $ foldMap S.singleton body
102+
rebind v' = elemIndex v' freeVars <|>
103+
guard (v' == v) *> (Just $ length freeVars)
104+
return $ FixC t (map VC freeVars) (abstract rebind body)
105+
closConv (Lam t bind) = do
106+
v <- gen
107+
body <- closConv (instantiate1 (V v) bind)
108+
let freeVars = S.toList . S.delete v $ foldMap S.singleton body
109+
rebind v' = elemIndex v' freeVars <|>
110+
guard (v' == v) *> (Just $ length freeVars)
111+
return $ LamC t (map VC freeVars) (abstract rebind body)
112+
113+
{- Lambda + Fixpoint lifting -}
114+
data BindL a = RecL Ty [ExpL a] (Scope Int ExpL a)
115+
| NRecL Ty [ExpL a] (Scope Int ExpL a)
116+
deriving (Eq, Functor, Foldable, Traversable)
117+
data ExpL a = VL a
118+
| AppL (ExpL a) (ExpL a)
119+
| LetL [BindL a] (Scope Int ExpL a)
120+
| SucL (ExpL a)
121+
| ZeroL
122+
deriving (Eq, Functor, Foldable, Traversable)
123+
124+
instance Eq1 ExpL where
125+
instance Applicative ExpL where
126+
pure = return
127+
(<*>) = ap
128+
instance Monad ExpL where
129+
return = VL
130+
VL a >>= f = f a
131+
AppL l r >>= f = AppL (l >>= f) (r >>= f)
132+
SucL e >>= f = SucL (e >>= f)
133+
ZeroL >>= _ = ZeroL
134+
LetL binds body >>= f = LetL (map go binds) (body >>>= f)
135+
where go (RecL t es scope) = RecL t (map (>>= f) es) (scope >>>= f)
136+
go (NRecL t es scope) = NRecL t (map (>>= f) es) (scope >>>= f)
137+
138+
trivLetBody :: Scope Int ExpL a
139+
trivLetBody = fromJust . closed . abstract (const $ Just 0) $ VL ()
140+
141+
llift :: (Eq a, Ord a, Enum a) => ExpC a -> Gen a (ExpL a)
142+
llift (VC a) = return (VL a)
143+
llift ZeroC = return ZeroL
144+
llift (SucC e) = SucL <$> llift e
145+
llift (AppC f a) = AppL <$> llift f <*> llift a
146+
llift (LamC t clos bind) = do
147+
vs <- replicateM (length clos + 1) gen
148+
body <- llift $ instantiate (VC . (!!) vs) bind
149+
clos' <- mapM llift clos
150+
let bind' = abstract (flip elemIndex vs) body
151+
return (LetL [NRecL t clos' bind'] trivLetBody)
152+
llift (FixC t clos bind) = do
153+
vs <- replicateM (length clos + 1) gen
154+
body <- llift $ instantiate (VC . (!!) vs) bind
155+
clos' <- mapM llift clos
156+
let bind' = abstract (flip elemIndex vs) body
157+
return (LetL [RecL t clos' bind'] trivLetBody)

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## pcf
2+
3+
A one file compiler for PCF to C. Not quite done yet.

Setup.hs

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import Distribution.Simple
2+
main = defaultMain

pcf.cabal

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: pcf
2+
version: 0.1.0.0
3+
synopsis: A one file compiler for PCF
4+
license: MIT
5+
license-file: LICENSE
6+
author: Danny Gratzer
7+
maintainer: [email protected]
8+
category: Compiler
9+
build-type: Simple
10+
extra-source-files: README.md
11+
cabal-version: >=1.10
12+
library
13+
exposed-modules: Pcf
14+
build-depends: base >=4.0 && <5
15+
, bound
16+
, containers
17+
, monad-gen
18+
, mtl
19+
, prelude-extras
20+
, void
21+
default-language: Haskell2010

0 commit comments

Comments
 (0)