Skip to content

Commit 5d78274

Browse files
committed
Implement exercise 3.38
1 parent 476f201 commit 5d78274

File tree

3 files changed

+38
-14
lines changed

3 files changed

+38
-14
lines changed

src/Evaluators/GMachine/Compiler.hs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ compileC (ELet isRec defs e) env | isRec = compileLetrec compileC defs e env
114114
| otherwise = compileLet compileC defs e env
115115
-- Mark 6: need to handle constructors
116116
compileC e@(EAp e1 e2) env
117-
| saturatedConstr $ spine = compiledConstr
117+
| saturatedConstr spine = compiledConstr
118118
| otherwise = compileC e2 env ++ compileC e1 (argOffset 1 env) ++ [Mkap]
119119
where
120120
-- Compiled code if constructor
@@ -132,11 +132,12 @@ compileC e@(EAp e1 e2) env
132132
spine' e' = [e']
133133
-- Special handling for nullary constructors
134134
compileC (EConstr t 0) _ = [Pack t 0]
135-
-- Other forms are invalid; they can only be reached via program transformations
136-
compileC (EConstr _ _) _ =
137-
error "compileC: constr incorrectly tagged with 0 args"
138-
compileC (ECase _ _) _ = error "compileC: case in non-strict context"
139-
compileC (ELam _ _) _ = error "compileC: lambda not implemented"
135+
-- Constructor applied to too few arguments; exercise 3.38
136+
compileC (EConstr t a) _ =
137+
[Pushglobal $ "Pack{" ++ show t ++ "," ++ show a ++ "}"]
138+
compileC (ECase _ _) _ =
139+
error "compileC: case in non-strict context; rewrite case as sc"
140+
compileC (ELam _ _) _ = error "compileC: lambda not implemented"
140141

141142
-- Compile a letrec expression
142143
compileLetrec :: GmCompiler -> [(Name, CoreExpr)] -> GmCompiler

src/Evaluators/GMachine/Evaluator.hs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import Evaluators.GMachine.State
77
import Alloc
88
import Data.AssocList
99
import Language
10+
import Lexer
11+
import Parser.Core
1012

1113
eval :: GmState -> [GmState]
1214
eval state = state : restStates
@@ -56,10 +58,28 @@ dispatch Print = printI
5658

5759
-- Push global onto stack
5860
pushglobal :: Name -> GmStateT
59-
pushglobal f state = state { gmStack = a : gmStack state }
61+
pushglobal f state = state { gmStack = a : gmStack state
62+
, gmHeap = h'
63+
, gmEnv = e'
64+
}
6065
where
61-
a =
62-
lookupDef (error $ "pushglobal: undeclared global: " ++ f) f $ gmEnv state
66+
-- Exercise 3.38: Pack{t,n} may need to be dynamically generated
67+
-- (introduced in Mark 6). These can also be generated at compile-
68+
-- time, but this complicates the signatures of the compile schemes.
69+
-- Probably inefficient to use a full parser for this, but it is
70+
-- convenient and only needs to be called when the Pack{t,n} is
71+
-- encountered for the first time. If the looked up variable is
72+
-- not of the form Pack{t,n}, then there is an undeclared global.
73+
h = gmHeap state
74+
e = gmEnv state
75+
(h', a, e') = getHeapAddr $ lookupDef hNull f $ gmEnv state
76+
where
77+
getHeapAddr a' | a' == hNull = updateEnv $ makePackSc $ pConstr $ clex f
78+
| otherwise = (h, a', e)
79+
updateEnv (h'', a') = (h'', a', (f, a') : e)
80+
makePackSc ((EConstr t n, []) : []) =
81+
hAlloc h $ NGlobal n [Pack t n, Update 0, Unwind]
82+
makePackSc _ = error $ "pushglobal: undeclared global: " ++ f
6383

6484
-- Allocate int and push onto stack
6585
-- Exercise 3.6: Reuse number nodes

src/Parser/Core.hs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module Parser.Core
77
, pLam
88
, pLet
99
, pCase
10+
, pConstr
1011
) where
1112

1213
import Language
@@ -34,21 +35,23 @@ pSc = pThen4 mk_sc pVar (pZeroOrMore pVar) pEq pExpr
3435
where mk_sc name args _ body = (name, args, body)
3536

3637
-- Parse an expression
37-
pExpr, pAtom, pCase, pLam, pAp, pLet :: Parser CoreExpr
38+
pExpr, pAtom, pCase, pLam, pAp, pLet, pConstr :: Parser CoreExpr
3839
pExpr = foldl1 pAlt [pLet, pCase, pLam, pExpr1]
3940

4041
-- Exercise 1.21: Complete the parser, except for EAp (and infix ops).
4142
-- Exercise 1.23: Implement mk_ap_chain for function application.
4243
pAtom = foldl1 pAlt [pEVar, pENum, pConstr, pWrappedExpr]
4344
where
44-
mk_constr _ eConstr _ = eConstr
4545
pEVar = pApply pVar EVar
4646
pENum = pApply pNum ENum
47-
pConstr = pThen3 mk_constr pPre pInd pRBkt
48-
pPre = pThen undefined pKwPack pLBkt
49-
pInd = pThen3 (\n1 _ n2 -> EConstr n1 n2) pNum pCom pNum
5047
pWrappedExpr = pThen3 (\_ e _ -> e) pLPar pExpr pRPar
5148

49+
pConstr = pThen3 mk_constr pPre pInd pRBkt
50+
where
51+
mk_constr _ eConstr _ = eConstr
52+
pPre = pThen undefined pKwPack pLBkt
53+
pInd = pThen3 (\n1 _ n2 -> EConstr n1 n2) pNum pCom pNum
54+
5255
pAp = pApply (pOneOrMore pAtom) mk_ap_chain where mk_ap_chain = foldl1 EAp
5356

5457
pLet = pThen4 mk_let pLetKw pDefns pKwIn pExpr

0 commit comments

Comments
 (0)