-
Notifications
You must be signed in to change notification settings - Fork 0
/
AST.hs
63 lines (57 loc) · 2.81 KB
/
AST.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
module Interpreter.AST ( reduceSExpr, bakeFreeVars ) where
import Control.Applicative
import Control.Monad.Except
import Control.Monad.State
import Data.Generics.Uniplate.Operations
import Data.Traversable
import Core.Types
import Core.Utils
reduceSExpr :: ParamList -> SExpr -> KLContext Env RSExpr
reduceSExpr args body = markBoundVars args (bakeFreeVars args body)
markBoundVars :: ParamList -> SExpr -> KLContext Env RSExpr
markBoundVars args = bake (length args) (zip args [0..])
where klTrue = Lit (B True)
klFalse = Lit (B False)
bake n args (Sym s)
| Just i <- lookup s args = pure (RDeBruijn i)
| otherwise = throwError "found bound symbol, should be a literal"
bake n args (Lambda s e)
| Just i <- lookup s args = RLambda i <$> bake n args e
| otherwise = RLambda n <$> bake (n+1) ((s,n):args) e
bake n args (Let v b e) = bake n args (Appl [Lambda v e, b])
bake n args (Lit a) = pure (RLit a)
bake n args (Freeze e) = RFreeze <$> bake n args e
bake n args (TrapError e tr) =
RTrapError <$> bake n args e <*> bake n args tr
bake n args (If c t f) =
RIf <$> bake n args c <*> bake n args t <*> bake n args f
bake n args (And c1 c2) =
bake n args (If c1 (If c2 klTrue klFalse) klFalse)
bake n args (Or c1 c2) =
bake n args (If c1 klTrue (If c2 klTrue klFalse))
bake n args (Cond ((c,e):cs)) = bake n args (If c e (Cond cs))
bake n args (Cond []) = pure REmptyList
bake n args (Appl [Lit (UnboundSym "read-byte")]) =
bake n args (Appl [Lit (UnboundSym "read-byte"),
Appl [Lit (UnboundSym "stinput")]])
bake n args (Appl [Lit (UnboundSym "write-byte"), b]) =
bake n args (Appl [Lit (UnboundSym "write-byte"), b,
Appl [Lit (UnboundSym "stoutput")]])
bake n args (Appl (Lit (UnboundSym a):as)) =
RApplDir <$> functionRef a <*> traverse (bake n args) as
bake n args (Appl (a:as)) =
RApplForm <$> bake n args a <*> traverse (bake n args) as
bake n args (Appl []) = bake n args EmptyList
bake n args EmptyList = pure REmptyList
bakeFreeVars :: ParamList -> SExpr -> SExpr
bakeFreeVars = bake'
where bake' args (Lambda sym expr) =
Lambda sym (bake' (sym:args) expr)
bake' args (Let sym bind expr) =
bake' args (Appl [Lambda sym expr, bind])
bake' args (Sym sym)
| sym `elem` args = Sym sym
| otherwise = Lit (UnboundSym sym)
bake' args expr = descend (bake' args) expr