forked from blynn/compiler
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgrind.lhs
144 lines (111 loc) · 4.54 KB
/
grind.lhs
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
= Level grinding =
We incrementally improve our compiler over and over again, which is like
grinding levels in a computer role-playing game. There is even a skill tree of
sorts. Do we want to add language features? Or optimize the generated code? Or
improve error reporting? And so on.
We must also prepare for an link:miranda.html[an upcoming boss battle].
== Stringy ==
Algorithm 4.1 of Kiselyov's paper; strings and character constants.
++++++++++
<script>
function hideshow(s) {
var x = document.getElementById(s);
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
</script>
<p><a onclick='hideshow("stringy");'>▶ Toggle Source</a></p>
<div id='stringy' style='display:none'>
++++++++++
------------------------------------------------------------------------
include::stringy[]
------------------------------------------------------------------------
++++++++++
</div>
++++++++++
== Binary ==
Lists; binary operators on the right-hand side.
We can now write `xs ++ ys` in expressions, though the function itself must be
defined with `(++) xs ys = ...`.
++++++++++
<p><a onclick='hideshow("binary");'>▶ Toggle Source</a></p>
<div id='binary' style='display:none'>
++++++++++
------------------------------------------------------------------------
include::binary[]
------------------------------------------------------------------------
++++++++++
</div>
++++++++++
== Algebraically ==
Algebraic data types, sections, case expressions, recursive definitions, but
not mutually recursive definitions.
Because of the link:scott.html[simplistic way we convert case expressions to
lambda calculus], our compiler expects case expressions to list out each data
constructor in the order they are given in their `data` declaration.
We pay a heavy price for simplicity. When a case expression is evaluated, we
copy the address of each alternative to the stack, only to eventually eliminate
all but one. Furthermore, we copy and delete these addresses by evaluating
intricate sequences of B and K combinators.
++++++++++
<p><a onclick='hideshow("algebraically");'>▶ Toggle Source</a></p>
<div id='algebraically' style='display:none'>
++++++++++
------------------------------------------------------------------------
include::algebraically[]
------------------------------------------------------------------------
++++++++++
</div>
++++++++++
== Parity ==
Achievement unlocked. GHC accepts our next compiler if we insert the following
preamble:
------------------------------------------------------------------------
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
import Prelude ((+), (-), (*), Char, Int, String, succ)
import Data.Char (chr, ord)
import qualified Prelude
a <= b = if a Prelude.<= b then True else False
(/) = Prelude.div
(%) = Prelude.mod
class Eq a where { (==) :: a -> a -> Bool };
instance Eq Char where { (==) x y = if (x Prelude.== y) then True else False };
instance Eq Int where { (==) x y = if (x Prelude.== y) then True else False };
------------------------------------------------------------------------
We can now develop using GHC with its powerful type checking and friendly
error messages. Naturally, we switch back to our compiler when it all works,
though we must be mindful that in our language, all operators have the same
precedence, every identifier in an expression we're parsing must have already
been defined, and case expressions require all data constructors to appear
exactly once and in order.
We drop support for the `@` prefix. Our language has advanced enough that we no
longer need direct access to primitive combinators.
This compiler supports integer constants. We've survived without them for
so long because the `succ` function has been enough for our numerical needs
so far.
++++++++++
<p><a onclick='hideshow("parity");'>▶ Toggle Source</a></p>
<div id='parity' style='display:none'>
++++++++++
------------------------------------------------------------------------
include::parity.hs[]
------------------------------------------------------------------------
++++++++++
</div>
++++++++++
== Fixity ==
This compiler supports `infix, infixl, infixr` declarations at the beginning of
the source.
++++++++++
<p><a onclick='hideshow("fixity");'>▶ Toggle Source</a></p>
<div id='fixity' style='display:none'>
++++++++++
------------------------------------------------------------------------
include::fixity.hs[]
------------------------------------------------------------------------